一、智慧导览系统介绍 手绘电子地图,就是把手绘地图覆盖到地图上,游客或者普通用户,可以在手机上通过地图的链接(或者现在流行的小程序)打开使用。是一种使用非常方便,集“视、听、路径规划、实时导航”等诸多功能于一体的智慧导览系统。也是现在很多景区为游客提供的增加便捷性和游玩体验的一项功能。 最重要的两点,我认为是: 1.手绘图本身 手绘图的美观度、清晰度、完整度、准确度,决定了图的档次格调的高低,也是手绘设计师的技术水平、设计能力、规划能力、沟通能力等综合性体现。 2.实时导航功能 如果说手绘图本身是面子,让人对地图有第一印象和直观感受,那么实时导航功能则是地图的灵魂和里子。没有实时定位和动态路径规划导航功能的地图,只是一个可观而不可用的花瓶,没有使用价值。没有准确的而高效的实时导航算法,就不能把地图价值在游客手里发挥到最大。
示例 二、智慧导览系统功能 先看一个参考示例图(根据实际情况,只添加了必要的功能): 参考示例图 编辑 1.基础功能 地图功能的设计,包括需要哪些功能,需要怎么展示,地图点位的图标等细节,不一而足。每个需求方可能要的也不一样。但总体来说,可能包含如下:
2.增强功能 智慧导览系统还应该具备如下增强功能,才能更好的增强客户的服务能力、满足用户的使用需求。这也是当前电子手绘地图系统的重点和难点。
3.地图个性化 智慧导览系统不应该是一个单纯的功能性的系统,还应该有更多丰富的、多元化的功能,为用户提供更多个性化、趣味化的服务。
示例 三、技术栈的选择 从这里开始后面的内容,有一定的行业背景或经验的人,能更好的理解。我尽量说得通俗易懂一些。如果你觉得一些专业名词不明白是什么意思,可以直接跳过。 现在绝大部分业务系统的开发,都是基于一个成熟的技术栈来实现。这样可以极大的节约基础设施的成本,而且效率得到极大的提高。甚至某些系统或行业的应用及系统,不基于一些成熟的技术栈,想要完全自主开发,几乎是不可实现的。 智慧导览系统,建议基于这样的一个技术栈: 1.服务器 使用成熟的云平台,国内成熟好用的几家,业内人都知道。 2.前端平台 如今最大的前端平台是微信小程序,还有就是浏览器直接通过链接打开。不过就智慧导览系统来说,大部分情况下,微信小程序也是基于Webview控件来调用,本质上和浏览器的直接打开没什么区别,就是HTML5+JavaScript+CSS3来实现。但是微信的生态内,会有一些微信开放的额外的一些接口和功能,比如说:可以使用微信提供的位置获取接口,来为游客获取更精准的定位。 3.地图平台 智慧导览系统只能基于地图的开放平台来实现。目前国内几家大而成熟的地图平台:高德地图、百度地图、腾讯地图。建议首选高德地图,次选百度地图。为什么呢?
示例 四、开发介绍 具体开发内容,这里主要介绍涉及地图核心的部分。其他比如数据库设计、后台管理系统等不做过多介绍。 1.开发语言选择
2.地图基础知识 这一点,是核心,基础中的基础,原理也比较复杂。因为地球是一个球体,是立体的,并不是天圆地方的一个平面,所以,首先,需要引入一个叫“坐标系统”的概念。 当前常见的坐标系主要有三种:
但是我们使用地图的时候,却又只能看到平面的地图,因此,又有了另外一个概念:墨卡托投影。
二维化之后的平面,会被分割为一片一片的小图,或者换句话说,由一片一片的小图拼成了二维的地图。而这个小图,叫“瓦片图”。这又是一个重要的概念。后文会继续细说。 而瓦片图的开始点(最左上角,或最左下角)在地球的什么地方呢,因为坐标系的不同,每个地图可能也不一样。所以,同一个经纬度,在不同的地图平台上,对应的瓦片图的序号可能都是不一样的。其中详细的原理和规则算法,这篇文章说得比较详细: 国内主要地图瓦片坐标系定义及计算原理 3.地图平台介绍 高德、百度、腾讯、谷歌地图开放平台介绍。 首先祭出开放平台文档,这是基于平台开发的基础:
每个地图的API,大同小异。从细节来说,腾讯地图的接口和高德地图差别最小。 值得一提的是,在地图上画线(主要是导航的线路规划标识),谷歌地图没有直接给出绘制虚线的接口,而国内的地图平台都有。这一点也体现了国内和国外的一种思维的差异。 另外还有一个细节,标注图标旋转(比如导航时,箭头图标跟随人的方向旋转)接口,高德地图的旋转的中心点不是图标中心,而是图标外层父元素的点位,因此转向时,给人的感觉是自身的位置也在画一个圆圈,而百度地图没有这个问题。当然这个问题也不是无法解决,我们可以通过自己编写转向的CSS,利用JavaScript来控制图标以中心点来转向。 图标围绕父元素边点转向 图标围绕中心点正常转向 每个地图平台在手机端的表现和体验也有些差异。我个人觉得高德地图最流畅顺滑,百度地图次之。 还有另外一点细节,就是关于瓦片图(后文细说),一样的图,在腾讯地图上会有非常细微的差别(腾讯地图允许级别Zoom为小数,在两个级别之间,还可以有多个过度值,而其他地图只能是整数,这是一个更人性化的设计,但却导致了瓦片图变得模糊了一点)。 4.瓦片图覆盖到地图上 瓦片图是尺寸为256px*256px的正方形图片。这样的图片,像瓦片盖房一样,覆盖为整个地图,所以称为“瓦片图”。
瓦片图覆盖到地图,这是整个手绘电子地图最核心、最基础的设施和功能。因为此,我们自己绘制的精美地图,才能够覆盖到地图平台上,做成我们个性化需求的地图。具体的实现,并没有想象的那么复杂。当然,经验丰富的程序员,可以设计出更科学的算法和加载逻辑。这里抛砖引玉,做一个示例(高德地图): var fileHost = 'https:///'; var tileLayer = new AMap.TileLayer.Flexible({ createTile: function (x, y, zoom, success, fail) { var imagePath = fileHost + '/tilefile/' + zoom + '/x + '_' + y + '.png'; var div = document.createElement('div'); var img = document.createElement('img'); img.onload = function () { div.appendChild(img); }; img.crossOrigin = "anonymous"; img.onerror = function () { fail() }; img.src = imagePath; success(div); } }); tileLayer.setMap(map); 这里AMap.TileLayer.Flexible方法是核心,这是高德地图提供的使用瓦片图的一个接口。他提供了一个div层(className为“amap-layer amap-flexible”)覆盖在底图之上,然后允许此方法返回仁义的元素,填充在256*256的瓦片图的方格里。因此,这里其实也可以更简单的直接返回一个img元素而不用div: var fileHost = 'https:///'; var tileLayer = new AMap.TileLayer.Flexible({ createTile: function (x, y, zoom, success, fail) { var imagePath = fileHost + '/tilefile/' + zoom + '/x + '_' + y + '.png'; var img = document.createElement('img'); img.onload = function () { success(img); }; img.crossOrigin = "anonymous"; img.onerror = function () { fail() }; img.src = imagePath; } }); tileLayer.setMap(map); 以上为高德地图的示例,其他地图原理相差不大,因此不再赘述。当然,这里只给了最基础的加载瓦片图的逻辑。事实上,根据实际情况,这里面还会做很多必要的其他业务逻辑的判断,比如,系统应当存储当前地图的瓦片图范围,超出范围的,就不要加载图片,或者加载一张透明的小图等。 这里列一下地图平台瓦片图的接口名,便于有需要的搜索使用: AMap.TileLayer.Flexible // 高德地图 BMap.TileLayer // 百度地图 TMap.ImageTileLayer // 腾讯地图 google.maps.ImageMapType // 谷歌地图 //需要注意的是,一些地图的接口允许传入参数:瓦片图的尺寸。不过建议默认为256较好,毕竟这是通用的默认尺寸。 5.瓦片图的制作 既然瓦片图是基础,那么我们如何从一张完整的手绘图制作成为256*256的多张瓦片图呢?可能设计师都能想到,直接用Photoshop切图即可,很简单。是的,常理来说是这样,但这有2个问题: (1)我们设计的图,往往不是刚好为256px的倍数,那么第一张切图,从什么地方开始?(即便是刚好为256的倍数,也不能从0像素开始切,后文细说) (2)我们切图出来之后,结合前文的地图基础知识,通过上面示例代码可见,最关键的是每个图的文件名,要和地图的级别Zoom、X轴的数值x、Y轴的数值y相对应。否则切出来的图,没有任何意义。 这两个问题,是制作有用的瓦片图的根本问题。 其实,在我们绘制手绘图片文件之前,就已经清晰的知道,我们绘制的内容到底是处于地图的什么区域。然后应当记录这个区域的起始点的经纬度。
然后通过经纬度、抹卡托、可见区域像素三者的转换算法,计算出当前手绘图分别在X轴和Y轴的第二张瓦片图的偏移像素,然后从此像素位置开始切图,并把计算得到的层级(Zoom)、X坐标(x)、Y坐标(y)的值作为对应的文件名保存切图。因此,说到这里,我们便都知道,这切图工作没办法由设计师来人工执行,只能由设计的专门算法的系统执行。
瓦片图切好之后,放到专门的文件服务器,然后前端代码便可调用,实现瓦片图覆盖于地图底图上展示。个性又漂亮的手绘地图便基本成型了(如上图“参考示例图”)。 6.动态规划路径的实现 漂亮个性的手绘电子地图完成之后,这还只是一个纯纯的地图展示,谈不上功能性的使用,更别说“智慧”。因此,我们还需要增加各项智慧能力的功能。这其中,最基础的又应当是“实时定位”及“动态路径规划”了。
具体如何实现,原理很简单。前端通过定位接口获取到用户当前的位置(需要注意的是,为了支持更全面的使用场景,可以考虑兼容微信及HTML5原生接口),然后系统计算当前位置与指定的点位之间的路线。 因此,这就需要我们根据实际情况,事先在系统里标注园区内的点位和路线,路线越详细越好。而通过这些点位和路线,要计算得到最短路径,关键则在于最短路径的“寻路算法”。算法可以自己设计,而目前很多伟大的科学家公开的很多最短路径算法则更为推荐。因为自己设计的算法难免可能会出现一些不可预料的BUG,而这些公开的算法经过严密的证明和大量使用的验证,使得计算效率以及可靠性都有很好的保证。 这也是我的个人经验,曾经我们自己设计的一个算法,在大部分情况下都能计算出正确的最短路径结果,但在某些情况下,却得到意外的结果,或发生计算消耗较多时间,效率低下的情况。 我推荐“迪杰斯特拉”算法,或“佛洛依德”算法。 //C语言版本的迪杰斯特拉算法 int a[1000][1000]; int d[1000];//d表示源节点到该节点的最小距离 int p[1000];//p标记访问过的节点 int i, j, k; int m;//m代表边数 int n;//n代表点数 int main() { scanf("%d%d",&n,&m); int min1; int x,y,z; for(i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); a[x][y]=z; a[y][x]=z; } for( i=1; i<=n; i++) d[i]=max1; d[1]=0; for(i=1;i<=n;i++) { min1 = max1; for(j=1;j<=n;j++) if(!p[j]&&d[j]<min1) { min1=d[j]; k=j; } p[k] = 1; for(j=1;j<=n;j++) if(a[k][j]!=0&&!p[j]&&d[j]>d[k]+a[k][j]) d[j]=d[k]+a[k][j]; } for(i=1;i<n;i++) printf("%d->",d[i]); printf("%d\n",d[n]); return 0; }
根据对当前用户的实时定位,通过最短路径算法,便能实现动态路径的规划。这便使得我们的手绘电子地图具备了最基础、最重要的导航功能。 7.自动触发的实现 通过实时定位获取到用户当前位置,系统判断位置是否和后台设定的点位接近。当距离已小于设置值的时候,电子地图系统便自动展示当前点位的介绍信息、语音讲解,或者商家推送的优惠券等。因此,我们的电子地图系统便越来越智能了。 而在此基础之上,我们可以相当的所有功能,都可以加载到电子地图系统上。由此我们的系统便优化成为真正的“智慧导览系统”。其他的更多的功能的实现,我便不再赘述,只对下列三个比较特别的功能再做一些简述。 8.多语言的实现 多语言是一个老生常谈的需求,也是一个系统国际化所必备的功能。对于智慧导览系统而言,我觉得有两个值得注意的点:
9.实现国内国外可同时访问地图 这一点需求,是根据实际情况来提的。因为国内和国外的地图基本上不能互通,因此我们的智慧导览系统应当解决这一痛点。 10.地图路线的采集和标注 系统的“动态路径规划”功能需要园区的路线数据为基础,因此系统应当提供路线采集和标注的配套工具,方便工作人员从现场采集路线的经纬度等信息。 五、结尾 本文是我个人基于“智慧导览系统”开发经验的一个大致的概括。整体来讲,写得比较粗陋和简略。很难作为一个方案或者教程,只当是我个人做一个总结罢了。如有不当之处,欢迎指正。也欢迎有兴趣的一起讨论。 |
|