用于传播MapView注释的功能,使得没有重叠

时间:2014-11-09 01:08:07

标签: ios algorithm geometry mapkit graph-algorithm

似乎很多人已经触及了重叠MKAnnotation视图的问题,并在缩放结束时和viewdidload上优雅地展开了它们。所以我想我只是想咬紧牙关并开出一个解决方案,但在此之前,我想在算法上提出建议。以前有关此主题的帖子没有提供可行的解决方案:

ios sdk MKMapView overlapping pins? Laying out overlapping rectangles

还有更多......

所以我想到的功能是这样的:(注意所有的CGRects都是相同的大小)

-(NSArray *)spreadOutTheseViews:(NSArray *)arrayofCGRects{



    ////////////////////////////////////
    //find out who overlaps with who..
    ////////////////////////////////////

    NSMutableArray *arrayOfArraysOfRects = [[NSMutableArray alloc] init];

    // 1. make an array to let you know which Rects have already been added to one of the sets
    int n = (int)[arrayofCGRects count];
    NSMutableArray *addedAlready = [[NSMutableArray alloc] init];
    for (id obj in arrayofCGRects ) {
        [addedAlready addObject:@0];
    }

    // 2. go through and add them if they overlap
    for (int i=0; i<[arrayofCGRects count]; i++) {
        if ([[addedAlready objectAtIndex:i] isEqualToValue:@(0)]) {

            CGRect rect1 = [[arrayOfArraysOfRects objectAtIndex:i] CGRectValue];
            [arrayOfArraysOfRects addObject:[[NSMutableArray alloc] initWithObjects:@(i), nil]];
            [addedAlready insertObject:@(1) atIndex:i];

            for (int j=0; j<[arrayofCGRects count]; j++){
                if (i!=j && [[addedAlready objectAtIndex:j] isEqualToValue:@(0)] ) {
                    CGRect rect2 = [[arrayOfArraysOfRects objectAtIndex:j] CGRectValue];
                    if (CGRectIntersectsRect(rect1,rect2)){
                        // check if they are overlapping, if so, add it to
                        [[arrayOfArraysOfRects lastObject] addObject:@(j)];
                        [addedAlready insertObject:@(1) atIndex:j];
                    }
                }
            }
        }
    }
    NSMutableArray *arrayofCGPoints = [[NSMutableArray alloc] init];
    //3. now that we have "clusters" of overlapping rects.. push them away from each other..
    for(NSArray *indexArray in arrayOfArraysOfRects){

        if ([indexArray count]==1){
            // just simply add the CGPoint
            CGRect rect =  [[arrayofCGRects objectAtIndex:(NSInteger)[indexArray firstObject]] CGRectValue];
            [arrayofCGPoints addObject:[NSValue valueWithCGPoint:rect.origin] ];

        }else{

            // heart of the algo..
            // Idea 1: get the average of the CGPoints to find the center of all of them, then find a ring with a specific radius that we can put them all on. Note this is a packing problem that I really dont have a better solution for..


        }



    }

    return arrayofCGPoints;

}

非常感谢任何帮助..

1 个答案:

答案 0 :(得分:0)

嗯,这不是最漂亮的解决方案..但我现在有一些工作,万一有人觉得这很有用..如果你有一个更优雅的解决方案,还请发帖!

-(NSArray *)spreadOutTheseViews:(NSArray *)arrayofCGRects{

bool doAnyOverlapStill = true;
int counter=0;
NSMutableArray *newArrayOfCGRects = [[NSMutableArray alloc] initWithArray:arrayofCGRects];

while (doAnyOverlapStill) {
    NSLog([NSString stringWithFormat:@"number of iters %d",counter]);

    for (int i=0; i<[arrayofCGRects count]; i++) {
        CGRect rect1 = [[newArrayOfCGRects objectAtIndex:i] CGRectValue];
        for (int j=0; j<=i; j++){
            if (i!=j) {
                CGRect rect2 = [[newArrayOfCGRects objectAtIndex:j] CGRectValue];
                bool intersect = CGRectIntersectsRect(rect1,rect2);
                if (intersect){

                    if (counter%4==0) {
                        // LEFT
                        NSLog(@"LEFT");
                        // which ever one is on the left, move it further to the left
                        double neededDistanceAdjustment =  5+MAX(rect1.size.width,rect2.size.width) - fabsf(rect2.origin.x - rect1.origin.x);
                        if (rect1.origin.x < rect2.origin.x) {
                            // move rect 1 left (subtract)
                            rect1.origin.x -= neededDistanceAdjustment;
                            [newArrayOfCGRects removeObjectAtIndex:i];
                            [newArrayOfCGRects insertObject:[NSValue valueWithCGRect:rect1] atIndex:i];

                        }else{
                            // move rect 2 left (subtract)
                            rect2.origin.x -= neededDistanceAdjustment;
                            [newArrayOfCGRects removeObjectAtIndex:j];
                            [newArrayOfCGRects insertObject:[NSValue valueWithCGRect:rect2] atIndex:j];
                        }

                    }else if (counter%4==1) {
                        // UP
                        NSLog(@"UP");
                        double neededDistanceAdjustment =  5+MAX(rect1.size.height,rect2.size.height) - fabsf(rect2.origin.y - rect1.origin.y);
                        if (rect1.origin.y < rect2.origin.y) {
                            // move rect 1 up (subtract)
                            rect1.origin.y -= neededDistanceAdjustment;
                            [newArrayOfCGRects removeObjectAtIndex:i];
                            [newArrayOfCGRects insertObject:[NSValue valueWithCGRect:rect1] atIndex:i];

                        }else{
                            // move rect 2 up (subtract)
                            rect2.origin.y -= neededDistanceAdjustment;
                            [newArrayOfCGRects removeObjectAtIndex:j];
                            [newArrayOfCGRects insertObject:[NSValue valueWithCGRect:rect2] atIndex:j];
                        }

                    }else if (counter%4==2) {
                        //RIGHT

                        NSLog(@"RIGHT");
                        double neededDistanceAdjustment =  5+MAX(rect1.size.width,rect2.size.width) - fabsf(rect2.origin.x - rect1.origin.x);

                        if (rect1.origin.x > rect2.origin.x) {
                            // move rect 1 right (add)
                            rect1.origin.y += neededDistanceAdjustment;
                            [newArrayOfCGRects removeObjectAtIndex:i];
                            [newArrayOfCGRects insertObject:[NSValue valueWithCGRect:rect1] atIndex:i];

                        }else{
                            // move rect 2 right (add)
                            rect2.origin.y += neededDistanceAdjustment;
                            [newArrayOfCGRects removeObjectAtIndex:j];
                            [newArrayOfCGRects insertObject:[NSValue valueWithCGRect:rect2] atIndex:j];
                        }

                    }else if (counter%4==3) {
                        // DOWN

                        NSLog(@"DOWN");
                        double neededDistanceAdjustment =  5+MAX(rect1.size.height,rect2.size.height) - fabsf(rect2.origin.y - rect1.origin.y);
                        if (rect1.origin.y > rect2.origin.y) {
                            // move rect 1 down (add)
                            rect1.origin.y += neededDistanceAdjustment;
                            [newArrayOfCGRects removeObjectAtIndex:i];
                            [newArrayOfCGRects insertObject:[NSValue valueWithCGRect:rect1] atIndex:i];

                        }else{
                            // move rect 2 down (add)
                            rect2.origin.y += neededDistanceAdjustment;
                            [newArrayOfCGRects removeObjectAtIndex:j];
                            [newArrayOfCGRects insertObject:[NSValue valueWithCGRect:rect2] atIndex:j];
                        }
                    }
                    // update newArrayOfCGRects
                    counter++;

                }
            }
        }
    }
    if (counter>100) {
        NSLog(@"error!!");
        return arrayofCGRects;


    }

    doAnyOverlapStill = [self doRectsOverlap:newArrayOfCGRects];
    if (!doAnyOverlapStill) {
        return newArrayOfCGRects;
    }
}

return arrayofCGRects;

}