1. 程式人生 > >判斷一個座標點是否在一個無規則的多邊形內 (iOS定位服務與地圖應用開發:高德地圖開發)

判斷一個座標點是否在一個無規則的多邊形內 (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,這是一個用於查詢的框架,有興趣的朋友可以多加研究。