手繪圖導航

簡介

通常在項目中需要用到地圖的時候我們會選擇百度、高德等地圖;但有的時候客戶會要求提供基于手繪圖的定位、導游導覽功能,百度-瓦片圖層高德-圖片覆蓋物提供了相應的解決方案,我們可以把手繪圖作為瓦片、覆蓋物放在地圖上,但是這種方案有其局限性:必須依托百度、高德地圖本身才能查看手繪圖。

接下來我將為大家帶來另外一種解決方案,純手繪圖導游導覽、定位,先看效果圖:

手繪圖導游導覽

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);
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容