判斷一個座標點是否在一個無規則的多邊形內 (iOS定位服務與地圖應用開發:高德地圖開發)
m
之前工作在一家智慧裝置的公司,做過一個親友定位監控系統,類似現在比較流行的360兒童手環。所以這裡簡單介紹定位與地圖。
1 定位服務
iOS裝置提供三種不同定位途徑,蜂窩式行動電話基站定位;WiFi定位,通過查詢一個WiFi路由器的地理位置資訊,比較省電;GPS衛星定位,通過3~4顆衛星定位,最為準確,但是耗電量大。iOS系統如果能夠接收GPS資訊,那麼裝置優先採用GPS,其次是WiFi,最後是基站,開發人員不能選擇哪種定位方式。
定位服務使用CoreLocation框架,主要使用CLLocationMananger、CLLocationManangerDelegate和CLLocation三個類,CLLocationMananger是定位服務管理類,獲取裝置的位置資訊,CLLocationManangerDelegate是代理協議,CLLocation封裝了位置資訊。
這裡要注意,CLLocationManangerDelegate 的locationManager:didUpdateToLocation:fromLocation:方法得到的座標是火星座標,這個原因你懂得,所以需要轉換成真實的地理座標。我使用的是一個第三方的CSqlite類,有一個轉換座標的資料庫,你呼叫就可以轉換為正確座標了。
得到經緯度後,要進行地理位置資訊反編碼,使用CLGeocoder類實現,將地理座標轉換為地理文字描述資訊,這些文字描述資訊被封裝在CLPlacemark類中。
當然給定地理資訊的文字描述,也可以進行地理資訊編碼查詢,轉換為地理座標,也是採用CLGeocoder類。
判斷一個座標點是否在一個無規則的多邊形內
// 在範圍內返回1,不在返回0 -(int)mutableBoundConrtolAction:(NSMutableArray *)arrSome:(CLLocationCoordinate2D )myCoordinate4{ int n=arrSome.count; float vertx[n]; float verty[n]; for (int i=0; i<arrSome.count; i++) { //MyPoint類儲存的是經度和緯度 vertx[i]=((MyPoint *)(arrSome[i])).x; verty[i]=((MyPoint *)(arrSome[i])).y; } if (arrSome.count==0) { return 1; } BOOL i=pnpoly(arrSome.count, vertx, verty, myCoordinate4.latitude, myCoordinate4.longitude); if (i) { return 1; }else{ return 0; } return 1; } //多邊形由邊界的座標點所構成的陣列組成,引數格式 該陣列的count, 多邊形邊界點x座標 的組成的陣列,多邊形邊界點y座標 的組成的陣列,需要判斷的點的x座標,需要判斷的點的y座標 BOOL pnpoly (int nvert, float *vertx, float *verty, float testx, float testy) { int i, j; BOOL c=NO; for (i = 0, j = nvert-1; i < nvert; j = i++) { if ( ( (verty[i]>testy) != (verty[j]>testy) ) && (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) ) c = !c; } return c; }
2 系統地圖
地圖我目前用過系統、百度以及高德,開發人員使用都是差不多的,下面的程式碼涉及的類都是高德地圖api提供的類。
我之前做專案,使用高德地圖,做到後期,專案會出現閃退,後來查出是地圖區域記憶體的問題,然後重新佈局了地圖區域,使得每一個地圖區域能夠及時銷燬,雖然閃退週期明顯延長,但是還是存在,這裡不知道是何原因,說來慚愧。
設定地圖區域
-(void)SetMapRegion:(CLLocationCoordinate2D)myCoordinate { MACoordinateRegion theRegion = { {0.0, 0.0 }, { 0.0, 0.0 } }; theRegion.center=myCoordinate; [self.m_map setScrollEnabled:YES]; theRegion.span.longitudeDelta = 0.01f; theRegion.span.latitudeDelta = 0.01f; [self.m_map setRegion:theRegion animated:YES]; }
平移地圖,上下左右
-(void)panMap:(NSString *)direction{ CLLocationCoordinate2D changeCoordinate=self.m_map.centerCoordinate; CGPoint changePoint=[self.m_map convertCoordinate:changeCoordinate toPointToView:self.m_map]; if ([direction isEqualToString:@"up"]) { changePoint.y=changePoint.y+50; }else if ([direction isEqualToString:@"down"]) { changePoint.y=changePoint.y-50; }else if ([direction isEqualToString:@"left"]) { changePoint.x=changePoint.x-50; }else if ([direction isEqualToString:@"right"]) { changePoint.x=changePoint.x+50; } changeCoordinate=[self.m_map convertPoint:changePoint toCoordinateFromView:self.m_map]; [self.m_map setCenterCoordinate:changeCoordinate animated:YES]; }
判斷某一個座標點是否在當前地圖區域內
-(void)isAtCurrentRegion:(CLLocationCoordinate2D)coordiante{ CGPoint point=[self.m_map convertCoordinate:coordiante toPointToView:self.view]; if ((point.x<0)||(point.y<0)||(point.x>WScreen)||(point.y>HScreen)) { // 如果不在 設定該點為地圖中心點 [self SetMapRegion:coordiante]; } }
在地圖上新增標註
系統地圖使用MapKit框架,核心是MKMapView類,顯示地圖只要新增MKMapView例項就可以了。如果要實現在地圖上新增標註點,第以是觸發新增動作,第二實現MKMapViewDelegate的mapView:viewForAnnotation:完成新增標註。
高德地圖實現的原理也是一樣的,高德地圖使用的是MAMapKit框架。對於annotation,一般會自定義一個繼承NSobject並且實現了maannotation協議的類,然後使用mapview的addAnnotation:方法就可以。MKReverseGeocoder類可以實現coordinate的反編碼,這裡需要實現它的代理,把得到的地理文字描述資訊賦給annotation。這裡需要實現代理的mapView:viewForAnnotation:方法,一個標註其實就是一個MAAnnotationView,標註有點類似tableviewcell,這裡也有重用機制。實現代理的mapView:annotationView:calloutAccessoryControlTapped:方法可以響應leftCalloutAccessoryView或者rightCalloutAccessoryView的點選事件,不過這個accessory
view必須繼承自UIControl。
在地圖上繪製線條和多邊形
MAPolyline類定義一個由多個點相連的多段線,點與點之間尾部想連但第一點與最後一個點不相連, 通常MAPolyline是MAPolylineView的model,它提供了兩個方法polylineWithPoints:count:、polylineWithCoordinates:count:用來新增線條,然後再通過map view的addOverlay:方法把Polyline例項新增進去,最後實現mapviewdelegate的mapView:viewForOverlay:方法就可以了。注意如果一開始新增的不是coordinate,而是point,可以通過map view的convertPoint:toCoordinateFromView:方法進行轉換。
MAPolygon類定義的就是一個不規則的由多個點組成的閉合多邊形,點與點之間按順序尾部相連, 第一個點與最後一個點相連, 通常MAPolygon是MAPolygonView的model,首先需要新增座標點的陣列,可以使用polygonWithCoordinates:count:方法或者polygonWithPoints:count:方法,然後把這個polygon通過addOverlay:方法新增到map view上就可以了。然後可以在mapviewdelegate裡面的mapView:viewForOverlay:方法裡面給MAPolygonView的屬性賦值,這樣一個完整的多邊形就出來了。
不管是高德地圖還是百度地圖等第三方,都會有一個mapsearchkit,這是一個用於查詢的框架,有興趣的朋友可以多加研究。