Как уменьшить количество аннотаций на карте?

Я кодирую представление карты примерно с 900 аннотациями. Наличие такого количества аннотаций на карте снижает производительность, поэтому я хотел бы уменьшить их примерно до 300 за раз. Аннотации представляют магазины в стране, поэтому они, как правило, группируются вокруг крупных городов, а затем небольшими группами по 2 или 3 в небольших городах. Я хочу уменьшить количество, чтобы группы из 2 или 3 остались в покое, но количество в городе уменьшилось (они настолько близко друг к другу, что не дают никакой полезной информации).

На изображении видно, что есть пара больших групп (Токио, Нагоя и Осака), которые я хочу проредить. Но с выводами по отдельности или небольшими группами я хочу убедиться, что они не будут отфильтрованы. Как только я увеличу масштаб, я хочу показать недостающие контакты.

Кто-нибудь знает какой-нибудь хороший код, который я могу использовать, чтобы точки, которые находятся близко друг к другу, удалялись, а более разбросанные оставались в покое?

http://img.skitch.com/20100204-jpde6wugc94nn692k7m36gmqf1.jpg


person nevan king    schedule 04.02.2010    source источник


Ответы (6)


Один из подходов заключается в том, что перед размещением новой булавки проверьте, не находится ли уже другая булавка на расстоянии d от новой булавки. Если есть, не ставьте новый штифт. Вам нужно изменить d в зависимости от текущего уровня масштабирования.

Вы можете уменьшить количество булавок, которые вы проверяете, рассматривая только булавки в ограничивающей рамке с центром на новой булавке. Сторона прямоугольника может иметь размеры d x d градусов (где d зависит от уровня масштабирования).

person Community    schedule 04.02.2010

Если вам нужна коммерческая сторонняя библиотека, попробуйте Superpin (стоимость лицензии – 199 долларов США). Это платформа iOS, которая внутри использует quadtrees для хранения аннотаций и выполняет кластеризацию на основе сетки. Алгоритм довольно быстрый, прилагаемый пример приложения показывает аэропорты мира (более 30 тысяч аннотаций), и он работает довольно гладко на 3G iPhone.

Вы также можете проверить http://revolver.be/blog/mapkit-clustering-with-ios/, еще одно готовое решение, бесплатное для некоммерческих проектов.

Отказ от ответственности: я являюсь одним из разработчиков Superpin

person esad    schedule 29.09.2011
comment
Я обнаружил, что довольно легко интегрировать проект револьвера с открытым исходным кодом в мое собственное приложение. Эсад спасибо! - person Eric Brotto; 19.03.2012

Два варианта, о которых я могу думать:

  • Если у вас есть точки интереса для работы (например, города), вы можете просто сгруппировать все булавки по POI, к которым они ближе всего, с более низким уровнем масштабирования.
  • Вы можете использовать кластеризацию K-средних, чтобы сгруппировать выводы в кластеры и представить их выводом в средней точке. .
person Nick Johnson    schedule 08.02.2010

Вот фрагмент кода, который берет координаты MKAnnotation, преобразует их в CGPoint относительно MKMapView и регистрирует базовое представление в этой CGPoint.

CGPoint pinPoint = [mapView convertCoordinate:pinView.annotation.coordinate toPointToView:mapView];
NSLog(@"pointing to %@", [[mapView hitTest:pinPoint withEvent:nil] description]);

Поместите это в цикл, который перебирает все ваши контакты. Если базовое представление является другим экземпляром MKAnnotation, скройте этот вывод.

if([[mapView hitTest:pinPoint withEvent:nil] isKindOfClass:[FFMapPinView class]])
    pinView.hidden = YES;

Чтобы это работало правильно, вам нужно, чтобы pinsArray был упорядочен так, чтобы индекс 0 был самым передним контактом.

person samvermette    schedule 11.10.2010
comment
интересный подход, хоть и не идеальный - person chatur; 10.01.2012

Учитывая, что многие булавки в густонаселенных районах будут на одной улице, вы можете подумать о создании «супер булавок», в которых перечислены булавки на конкретной улице, а не по каждому отдельному адресу.

-S!

person Stephen Furlani    schedule 04.02.2010

Я знаю, что опаздываю на вечеринку, но эта рутина может оказаться вам полезной. Он взят из этого файла, который является частью проекта FOSS.

/**************************************************************//**
 \brief This function looks for meetings in close proximity to each
        other, and collects them into "red markers."
 \returns an NSArray of BMLT_Results_MapPointAnnotation objects.
 *****************************************************************/
- (NSArray *)mapMeetingAnnotations:(NSArray *)inResults ///< This is an NSArray of BMLT_Meeting objects. Each one represents a meeting.
{
#ifdef DEBUG
    NSLog(@"BMLTMapResultsViewController mapMeetingAnnotations - Checking %d Meetings.", [inResults count]);
#endif
    NSMutableArray  *ret = nil;

    NSInteger   displayIndex = 1;

    if ( [inResults count] )
        {
        NSMutableArray  *points = [[NSMutableArray alloc] init];
        for ( BMLT_Meeting *meeting in inResults )
            {
#ifdef DEBUG
            NSLog(@"BMLTMapResultsViewController mapMeetingAnnotations - Checking Meeting \"%@\".", [meeting getBMLTName]);
#endif
            CLLocationCoordinate2D  meetingLocation = [meeting getMeetingLocationCoords].coordinate;
            CGPoint meetingPoint = [(MKMapView *)[self view] convertCoordinate:meetingLocation toPointToView:nil];
            CGRect  hitTestRect = CGRectMake(meetingPoint.x - BMLT_Meeting_Distance_Threshold_In_Pixels,
                                             meetingPoint.y - BMLT_Meeting_Distance_Threshold_In_Pixels,
                                             BMLT_Meeting_Distance_Threshold_In_Pixels * 2,
                                             BMLT_Meeting_Distance_Threshold_In_Pixels * 2);

            BMLT_Results_MapPointAnnotation *annotation = nil;
#ifdef DEBUG
            NSLog(@"BMLTMapResultsViewController mapMeetingAnnotations - Meeting \"%@\" Has the Following Hit Test Rect: (%f, %f), (%f, %f).", [meeting getBMLTName], hitTestRect.origin.x, hitTestRect.origin.y, hitTestRect.size.width, hitTestRect.size.height);
#endif

            for ( BMLT_Results_MapPointAnnotation *annotationTemp in points )
                {
                CGPoint annotationPoint = [(MKMapView *)[self view] convertCoordinate:annotationTemp.coordinate toPointToView:nil];
#ifdef DEBUG
                NSLog(@"BMLTMapResultsViewController mapMeetingAnnotations - Comparing the Following Annotation Point: (%f, %f).", annotationPoint.x, annotationPoint.y);
#endif

                if ( !([[annotationTemp getMyMeetings] containsObject:meeting]) && CGRectContainsPoint(hitTestRect, annotationPoint) )
                    {
#ifdef DEBUG
                    for ( BMLT_Meeting *t_meeting in [annotationTemp getMyMeetings] )
                        {
                        NSLog(@"BMLTMapResultsViewController mapMeetingAnnotations - Meeting \"%@\" Is Close to \"%@\".", [meeting getBMLTName], [t_meeting getBMLTName]);
                        }
#endif
                    annotation = annotationTemp;
                    }
                }

            if ( !annotation )
                {
#ifdef DEBUG
                NSLog(@"BMLTMapResultsViewController mapMeetingAnnotations -This meeting gets its own annotation.");
#endif
                NSArray *meetingsAr = [[NSArray alloc] initWithObjects:meeting, nil];  
                annotation = [[BMLT_Results_MapPointAnnotation alloc] initWithCoordinate:[meeting getMeetingLocationCoords].coordinate andMeetings:meetingsAr andIndex:0];
                [annotation setDisplayIndex:displayIndex++];
                [points addObject:annotation];
                }
            else
                {
#ifdef DEBUG
                NSLog(@"BMLTMapResultsViewController mapMeetingAnnotations -This meeting gets lumped in with others.");
#endif
                [annotation addMeeting:meeting];
                }

            if ( annotation )
                {
                if ( !ret )
                    {
                    ret = [[NSMutableArray alloc] init];
                    }

                if ( ![ret containsObject:annotation] )
                    {
                    [ret addObject:annotation];
                    }
                }
            }
        }

    // This is the black marker.
    BMLT_Results_MapPointAnnotation *annotation = [[BMLT_Results_MapPointAnnotation alloc] initWithCoordinate:[[BMLTAppDelegate getBMLTAppDelegate] searchMapMarkerLoc] andMeetings:nil andIndex:0];

    if ( annotation )
        {
        [annotation setTitle:NSLocalizedString(@"BLACK-MARKER-TITLE", nil)];
        [ret addObject:annotation];
        }

    return ret;
}

Вы можете увидеть его в действии в выпущенной версии приложения.

Встречи в непосредственной близости собраны в красные аннотации, которые открывают список.

person Chris Marshall    schedule 22.04.2012