Как уменьшить количество аннотаций на карте?
Я кодирую карту с примерно 900 аннотациями. Наличие этого большого количества аннотаций на карте ухудшает производительность, поэтому я хотел бы уменьшить ее до 300 за раз. Аннотации представляют собой магазины в стране, поэтому они, как правило, группируются вокруг крупных городов, а затем в небольших группах по 2 или 3 в небольших городах. Я хочу уменьшить числа, чтобы группы из 2 или 3 остались в одиночестве, но числа в городе истощены (они так близки друг к другу, что они не дают никакой полезной информации).
На изображении вы можете увидеть, что есть несколько больших групп (Токио, Нагоя и Осака), которые я хочу истощить. Но с булавками самостоятельно или небольшими группами я хочу убедиться, что они не фильтруются. Как только я увеличиваю масштаб, я хочу показать отсутствующие контакты.
Кто-нибудь знает о каком-то хорошем коде, который я могу использовать, так что точки, которые находятся близко друг к другу, устраняются, но те, которые более распространены, остаются в одиночестве?
alt text http://img.skitch.com/20100204-jpde6wugc94nn692k7m36gmqf1.jpg
Ответы
Ответ 1
Один из подходов заключается в том, что перед установкой нового штыря проверьте, есть ли еще один штырь, уже установленный на расстоянии d нового штыря. Если есть, не устанавливайте новый штырь. Вам необходимо изменить d на основе текущего уровня масштабирования.
Вы можете уменьшить количество выводов, которые вы проверяете, рассматривая только штифты в ограничивающей рамке с центром на новом булавке. Коробка может быть d x d градусов на стороне (с изменением d в зависимости от уровня масштабирования).
Ответ 2
Если коммерческая, сторонняя библиотека является опцией, проверьте Superpin (лицензия стоит 199 долларов США). Это iOS Framework, которая внутренне использует квадранты для хранения аннотаций и выполняет кластеризацию на основе сетки. Алгоритм довольно быстр, приложение с образцом включает показ аэропортов мира (более 30 тыс. Аннотаций), и он работает довольно гладко на 3G-iPhone.
Вы также можете проверить http://revolver.be/blog/mapkit-clustering-with-ios/, другое готовое решение, бесплатное для некоммерческих проектов.
Отказ от ответственности: я один из разработчиков Superpin
Ответ 3
Два варианта, о которых я могу думать:
- Если у вас есть интересные места для работы с (например, городами), вы можете просто сгруппировать все контакты с помощью ближайшей к ней точки интереса, с более низким уровнем масштабирования.
- Вы можете использовать K-mean clustering, чтобы группировать контакты в кластеры и представлять их с выводом средней точки.
Ответ 4
Здесь фрагмент кода, который принимает координаты 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 был самым верхним выводом.
Ответ 5
Учитывая, что многие штыри в густонаселенных районах будут находиться на одной и той же улице, вы можете подумать о том, чтобы сделать "супер булавки", которые перечисляют контакты на определенной улице, а не по каждому отдельному адресу.
-S
Ответ 6
Поздно к вечеринке, я знаю, но вы можете найти эту рутину полезной. Это этот файл, который является частью проекта 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;
}
Вы можете увидеть его в действии в выпущенной версии приложения.
Встречи в непосредственной близости собраны в красные аннотации, которые открывают список.