手绘图导航

作者: TroyZhang | 来源:发表于2016-05-05 18:24 被阅读620次

    简介

    通常在项目中需要用到地图的时候我们会选择百度、高德等地图;但有的时候客户会要求提供基于手绘图的定位、导游导览功能,百度-瓦片图层高德-图片覆盖物提供了相应的解决方案,我们可以把手绘图作为瓦片、覆盖物放在地图上,但是这种方案有其局限性:必须依托百度、高德地图本身才能查看手绘图。

    接下来我将为大家带来另外一种解决方案,纯手绘图导游导览、定位,先看效果图:

    手绘图导游导览

    NAMapKit

    NAMapKit是一个开源的手绘图框架,支持缩放、地图标记、高清地图切片浏览、本地手绘图、在线手绘图功能。

    NAMapKit Demo

    Popup Menu

    默认情况下NAMapKit的标记点弹出框不够nice,所以我在github上fork了NAMapKit,并实现了与City Guides by National Geographic这款App中类似的功能:

    Fork NAMapKit on github

    标记点

    普通点标记

    普通点的标记可以直接用尺子在手绘图上量一下,拿到目标点的CGPoint(x,y),之后把这个point作为NAPinAnnotation添加到地图上,这样就实现了打点的功能。

    当前位置打点

    要实现当前位置打点,就得将经纬度坐标转换成图片的平面坐标,以百度地图来说,它提供了以下转换函数:

    // BMKGeometry.h
    /**
     *将经纬度坐标转换为投影后的直角地理坐标
     *@param coordinate 待转换的经纬度坐标
     *@return 转换后的直角地理坐标
     */
    UIKIT_EXTERN BMKMapPoint BMKMapPointForCoordinate(CLLocationCoordinate2D coordinate);
    
    /**
     *将投影后的直角地理坐标转换为经纬度坐标
     *@param mapPoint 投影后的直角地理坐标
     *@return 转换后的经纬度坐标
     */
    UIKIT_EXTERN CLLocationCoordinate2D BMKCoordinateForMapPoint(BMKMapPoint mapPoint);
    

    这里有一个问题:以一个城市为例,在百度地图16、17、18、19等缩放级别下都可以绘制这个城市,但在16、17、18、19级别下画出来的手绘图的尺寸(像素)肯定是不一样的!那么百度地图的直角坐标是以什么为标准呢?

    • 以百度地图18级缩放级别为模板绘出的手绘图,其与百度地图的直角地理坐标是1:1的关系(zoomRate)
    • 你可以在百度地图上找一条直线,看这条直线在16、17、18、19级下长度分别是多少,然后以18级的长度为基准,可以计算出每个缩放等级下的比例值(zoomRate)

    所以,如果确定某个经纬度点肯定在当前手绘图中,则可以利用如下公式将经纬度坐标转换成手绘图的平面坐标

    // 如果手绘图是以百度地图18级为参照画出来的,则zoomRate为1
    #define zoomRate            1
    
    // 手绘图左上角点的经纬度坐标转换成百度地图的直角坐标
    BMKMapPoint leftTopCoor = BMKMapPointForCoordinate(CLLocationCoordinate2DMake(lat, lng))
    
    /**
     * 将经纬度坐标转换成手绘图的平面(像素)坐标
     */
    - (CGPoint)locationCoordToCgPoint:(CLLocationCoordinate2D)coor
    {
        BMKMapPoint point = BMKMapPointForCoordinate(coor);
        return CGPointMake((point.x - leftTopCoor.x) * zoomRate, (point.y - leftTopCoor.y) * zoomRate);
    }
    
    /**
     * 将手绘图的平面(像素)坐标转换成经纬度坐标
     */
    - (CLLocationCoordinate2D)cgPointToLocationCoord:(CGPoint)point
    {
        BMKMapPoint mapPoint;
        mapPoint.x = point.x / zoomRate + leftTopCoor.x;
        mapPoint.y = point.y / zoomRate + leftTopCoor.y;
        return BMKCoordinateForMapPoint(mapPoint);
    }
    
    判断给定经纬度是否在当前手绘图视野范围内
    // 其中imageWidth、imageHeight为手绘图的像素大小(px单位)
    - (BOOL)isLocationInImage:(CLLocationCoordinate2D)coor
    {
        CGPoint point = [self locationCoordToCgPoint:coor];
        return !(point.x < 0 || point.y < 0 || point.x > imageWidth || point.y > imageHeight);
    }
    

    相关文章

      网友评论

      • 6ca793a7723c:这个没有导航功能吗,如果要实现导航 功能有什么 建议
      • 傅hc:大兄弟,感谢分享好文,对于地图切片这一块有什么干货建议?
        TroyZhang:@傅hc 我觉得这个要看app是独立于百度/高德等地图之外、还是跟百度/高德地图结合;
        如果是前者,则稍微简单一点,美工制作好地图之后开发人员直接借助`dzt`等工具切瓦片图即可;
        如果是后者,则美工制作手绘图时最好严格按照256x256的比例来制作底图,底图的4个边与百度/高德地图的瓦片的边是贴合的,这样方便切瓦片、以及后面对瓦片重命名、并完美贴合在百度/高德地图上。
        傅hc:@TroyZhang :+1: 谢谢大兄弟,不过我昨天已经看了感觉还是少了一条线连接起来~~就是怎么把这些东西都连接起来~~
        TroyZhang:@傅hc 看看这个对你有没有帮助。http://www.jianshu.com/p/e9922962d508
      • 一首好听的歌:你好,你的demo源码能发我一份吗?现在公司让做手绘地图导航和定位以及路线规划的工能,我不知道从哪下手,你的源码能让我参考一下吗?我邮箱:18337165667@163.com,谢谢你
        TroyZhang:@一首好听的歌 不客气。
        一首好听的歌:@TroyZhang 谢谢你 :blush:
        TroyZhang:@一首好听的歌 链接: http://pan.baidu.com/s/1hs4SHJe 密码: rgdd
      • csqingyang:好文。第一张图导游导览中有两个问题需要请教一下:1 展示出来的地图使用的是先绘制好的图片然后将路线作为 overLay 添加上去的吗?2 有一个需求:将现实路线绘制成卡通路线,这里是否需要使用比如高德地图进行路径绘制(数据是怎么来的)?
        6ca793a7723c:这个没有导航功能吗,如果要实现导航 功能有什么 建议
        csqingyang:@TroyZhang:再赞一下!
        TroyZhang:@csqingyang 这里没有涉及到线路,美工做图的时候把线路也做进去了。

      本文标题:手绘图导航

      本文链接:https://www.haomeiwen.com/subject/duenlttx.html