根據坐標點顯示地圖顯示范圍(高德地圖)


 

 

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

過濾不合理點   CLLocationCoordinate2DIsValid 就可以搞定。。。。0.0

 

 

 

====================分割線啊分割線===以下活脫重新造了把輪子============================

 

/**

 *  過濾不合理點

 *

 *  @param locations locations description

 *

 *  @return return value description

 */

-(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 。

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

 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM