标签:
/** * 根据多个坐标点 设置当前map 显示区域 * * @param locations CLLocation 数组 * @param animate 动画 */ - (void)setMapBounds:(NSArray *)locations animated:(BOOL)animate{ if (!locations) { return; } if ([locations count] == 0) { return; } NSMutableArray *showArr = [NSMutableArray arrayWithCapacity:0]; MKCoordinateRegion region; __block CLLocationCoordinate2D topLeftCoord; __block CLLocationCoordinate2D bottomRightCoord; if ([locations count]>1) { topLeftCoord.latitude = -90; topLeftCoord.longitude = 180; bottomRightCoord.latitude = 90; bottomRightCoord.longitude = -180; /** * 过滤不合理的点 */ showArr = [self getShowAnnotationArr:locations]; //计算跨度 [showArr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { CLLocation * annotation = showArr[idx]; topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude); topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude); bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude); bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude); }]; region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5; region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5; region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.4; // Add a little extra space on the sides region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.4; // Add a little extra space on the sides if (region.span.longitudeDelta >=180) { region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; } MKCoordinateRegion fitRegion = [_mapView regionThatFits:region]; //兼容ios6 if (!isnan(fitRegion.center.latitude)) { region = fitRegion; } }else{ CLLocation * annotation = locations[0]; region.center = annotation.coordinate; region.span.latitudeDelta = 0.01f; region.span.longitudeDelta = 0.01f; } dispatch_async(dispatch_get_main_queue(), ^{ [_mapView setRegion:region animated:animate]; }); } /** * 过滤不合理点 * * @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 = [NSMutableArray arrayWithCapacity:0]; if ([nArr count]>[wArr count]&&[wArr count]>0) { NSMutableArray *rangInArr = [NSMutableArray arrayWithCapacity:0];// -90 <=w<=90 NSMutableArray *rangOutArr = [NSMutableArray arrayWithCapacity:0];// w<=-90 && w >=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]; //转西经 [wArr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { CLLocation * annotation = wArr[idx]; CGFloat tunrnWLon = 0.0; 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 if([wArr count]>[nArr count]&& [nArr count]>0){ NSMutableArray *rangInArr = [NSMutableArray arrayWithCapacity:0];// -90 <=w<=90 NSMutableArray *rangOutArr = [NSMutableArray arrayWithCapacity:0];// w<=-90 && w >=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; }else{ showArr = rangOutArr; } [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]; [nArr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { CLLocation * annotation = nArr[idx]; CGFloat tunrnNLon = 0.0; if (annotation.coordinate.longitude <=0 && annotation.coordinate.longitude>=-90) { tunrnNLon = annotation.coordinate.longitude; }else{ tunrnNLon = 180 +(180 +annotation.coordinate.longitude); } [wArr addObject:annotation]; }]; showArr = wArr; }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 。
....貌似有点稀里糊涂。希望有地理帝 给指点一二,说说其中原理。和这个算法的正确与否。
目前项目中这个算法运行良好,有不同建议欢迎讨论。
标签:
原文地址:http://www.cnblogs.com/tangbinblog/p/4505769.html