码迷,mamicode.com
首页 > 其他好文 > 详细

根据坐标点显示地图显示范围(高德地图)

时间:2015-05-15 15:07:25      阅读:1976      评论:0      收藏:0      [点我收藏+]

标签:

/**
 *  根据多个坐标点 设置当前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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!