對於如下問題系統方法有實現: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 。
....貌似有點稀裏糊塗。但願有地理帝 給指點一二,說說其中原理。和這個算法的正確與否。
目前項目中這個算法運行良好,有不一樣建議歡迎討論。