根據座標點顯示地圖顯示範圍(高德地圖)

 

 

對於如下問題系統方法有實現:git

過濾不合理點   CLLocationCoordinate2DIsValid 就能夠搞定。。。。0.0算法

 

 

 

====================分割線啊分割線===如下活脫從新造了把輪子============================數組

 

/**ide

 *  過濾不合理點spa

 *code

 *  @param locations locations descriptionblog

 *ip

 *  @return return value descriptionci

 */rem

-(NSMutableArray *)getShowAnnotationArr:(NSArray *)locations{

    CGFloat minLon = -90;

    CGFloat maxLon = 90;

    //解決跨國際日期變動線時 跨度計算錯誤

    NSMutableArray *nArr = [NSMutableArray arrayWithCapacity:0];//東經 

    NSMutableArray *wArr = [NSMutableArray arrayWithCapacity:0];//西經 

    

    //把座標點按東經  西經 分組

    [locations enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

        CLLocation * annotation = locations[idx];

        if (fmin(0.0, annotation.coordinate.longitude) == 0) {

            [nArr addObject:annotation];

        }else{

            [wArr addObject:annotation];

        }

    }];

    //最終轉換後,能夠顯示在地圖上得點

    NSMutableArray *showArr = nil;

    //判斷 按(東、西)經度的兩個分組, 最少的轉成最多的(好比東經少於西經,那麼將東經轉成西經表示)

    if ([nArr count] != [wArr count] && [wArr count]>0 && [nArr count]>0) {

        NSMutableArray *rangInArr = [NSMutableArray arrayWithCapacity:0];//  -90 <=lon<=90 範圍內的點

        NSMutableArray *rangOutArr = [NSMutableArray arrayWithCapacity:0];//  lon <=-90 && lon >=90 範圍內的點

        

        //將全部座標點按 上面範圍分組

        [locations enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

            CLLocation * annotation = locations[idx];

            if (annotation.coordinate.longitude >=minLon && annotation.coordinate.longitude <=maxLon) {

                [rangInArr addObject:annotation];

            }else{

                [rangOutArr addObject:annotation];

            }

            

        }];

        // 將最少的一組剔除,保留最多的一組。便可以正常顯示的點

        if ([rangOutArr count]<[rangInArr count]) {

            showArr = [rangInArr mutableCopy];

        }else{

            showArr = [rangOutArr mutableCopy];

        }

        //清空第一次分組後東西經分組。

        [wArr removeAllObjects];

        [nArr removeAllObjects];

        //從新裝入數據(這時是已通過濾了的數據,再次分組按東、西經)

        [showArr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

            CLLocation * annotation = showArr[idx];

            if (fmin(0.0, annotation.coordinate.longitude) == 0) {

                [nArr addObject:annotation];

            }else{

                [wArr addObject:annotation];

            }

        }];

        [showArr removeAllObjects];

        

        if ([wArr count] > [nArr count]) {

            //將東經 轉換爲 西經

            [nArr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

                CLLocation * annotation = nArr[idx];

                

                CGFloat tunrnNLon = 0.0;

                if (annotation.coordinate.longitude >=90  && annotation.coordinate.longitude<= 180) {

                    tunrnNLon =  -180+(annotation.coordinate.longitude - 180);

                }else{

                    tunrnNLon = annotation.coordinate.longitude;

                }

                

                CLLocation *newLoctaion = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:tunrnNLon];

                

                [wArr addObject:newLoctaion];

            }];

            showArr = wArr;

        }else{

            //將西經 轉換爲東經

            [wArr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

                CLLocation * annotation = wArr[idx];

                

                CGFloat tunrnWLon = 0.0;

                /**

                 *  轉換規則

                 *  若是 西經在 w<=0 && w>=-90 則東經必定在 0<= n <=90 則不須要處理。

                 *  相反  -90<= w <=-180  時,則東經必定在   90<= n <= 180 須要處理,把西經轉換爲東經。

                 *  由於若是不轉換在 算經度跨度  maxW - minW*係數  >= 180。則地圖顯示不出,會崩掉。

                 */

                if (annotation.coordinate.longitude <=0 && annotation.coordinate.longitude>=-90) {//

                    tunrnWLon = annotation.coordinate.longitude;

                }else{

                    tunrnWLon = 180 +(180 +annotation.coordinate.longitude);

                }

                CLLocation *newLoctaion = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:tunrnWLon];

                [nArr addObject:newLoctaion];

            }];

            //轉換後的點(都是以東經表示的電,即都是正數)

            showArr = nArr;

        }

        

        

    }else{

        showArr = [NSMutableArray arrayWithArray:locations] ;

    }

    return showArr;

}

 

說明:

       該算法原型 http://stackoverflow.com/questions/10222308/zoom-mapview-to-a-region-where-pins-are-dropped

 原算法在大部分狀況下效果不錯。但有個bug .

  

region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; 

    // Add a little extra space on the sides 
    region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; 

這段代碼若是在計算的數組裏包含  西經-175 東經175的狀況下就會奔潰。緣由是地圖只能顯示 經度跨度小於或等於180的區域。參與計算後結果會大於180.

 region = [mapView regionThatFits:region];

 執行後也依然如此。

緯度則不會出現這種狀況。北緯90 到 南緯-90 怎麼也不會出現大於180 的緯度跨度出現。

 

即若是數組裏有跨國際日期變動線 的座標點存在時。就會出現這種狀況。如新西蘭 就是個跨國際日期變動線的國家

國際日期變動線(西經-180 和 東經180 重合的那條線 ),能夠理解地球被 經度0 和國際日期變動線所繞的」圓「 切成東西半球。

 

我得解決辦法是 將數組安 東經(+)和 西經(-)分組。比較count 。若是東經 的座標點 大於西經。則轉換 西經爲 」東經「(一個正數)。

如: 西經 -176  轉東經 爲 180+(180+(-176))。是的,按照東經的增加順序  將西經轉換成一個大於180的 正數。而後參與計算。並平均出來。

東經轉西經也是一樣道理。

 

改進後對於大多數 狀況下新算法 顯示正常。即便是跨國際日期變動線。可是 依然有些狀況下會超出 180在最後計算出得經度跨度值。

例如:

一個 西經-40 的點  和  東經176 的點。

計算出來 經度跨度依然會大於 180.

鬱悶了一段時間,發現了個規律。

 就是顯示的區域要麼在

-90 ~0~90

 

-180 ~0

0~180

想象一個球,你均勻的切兩刀(豎着切沒有切開)變成4瓣。旋轉這個球每次旋轉90度。就會出現上面的假設。

在遵循上面假設的前提下,若是你要看 東經 90到180這個跨度裏的任一點,和 西經 -90到0這個跨度裏的任一點。即 連個不是相鄰的連個瓣你須要」透視眼「。沒辦法在平面上顯如今。

全部根據這個原理,我把不屬於-90 ~0~90的點和 屬於這個區域的點分開。

剔除不屬於這個區域的點,就是最後能夠正常顯示在地圖上且經度跨度不會超過180 。

....貌似有點稀裏糊塗。但願有地理帝 給指點一二,說說其中原理。和這個算法的正確與否。

 

目前項目中這個算法運行良好,有不一樣建議歡迎討論。

相關文章
相關標籤/搜索