2010-02-04 12 views
17

Estoy codificando una vista de mapa con alrededor de 900 anotaciones. Tener tantas anotaciones en un mapa hace que la performance se resienta, por lo que me gustaría reducirla a unas 300 a la vez. Las anotaciones representan tiendas en un país, por lo que tienden a agruparse mucho alrededor de las ciudades principales, luego en pequeños grupos de 2 o 3 en ciudades más pequeñas. Quiero reducir los números para que los grupos de 2 o 3 se queden solos, pero los números en la ciudad se adelgazan (están tan juntos que no ofrecen información útil).¿Cómo puedo reducir el número de anotaciones en un mapa?

En la imagen se puede ver que hay un par de grandes grupos (Tokio, Nagoya y Osaka) que quiero reducir. Pero con los pines solos o en grupos pequeños, quiero asegurarme de que no se filtren. Una vez que hago zoom, quiero mostrar los pines faltantes.

¿Alguien sabe de algún buen código que puedo usar, de modo que se eliminen los puntos que están muy juntos, pero los que están más dispersos se quedan solos?

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

Respuesta

6

Un enfoque es que antes de la colocación de un pasador nuevo, comprobar si hay otro pin ya colocado dentro de la distancia d de la nueva pin. Si hay, no coloque el nuevo pin. Debe variar d en función del nivel de zoom actual.

Puede reducir el número de pines que compara al considerar solo los pines en un cuadro delimitador centrado en el nuevo pin. La caja podría ser d x d grados en un lado (con d que varía según el nivel de zoom).

0

Teniendo en cuenta que muchos pines en áreas densamente pobladas estarán en la misma calle, podría considerar hacer "súper pines" que enumeren los pines en una calle en particular, en lugar de en cada dirección individual.

-S!

5

Dos opciones que se me ocurren:

  • Si usted tiene puntos de interés de trabajar con (por ejemplo, ciudades), puede simplemente grupos de todos los pines de la PDI que están más cerca, en menor zoom niveles.
  • Puede usar K-means clustering para agrupar pines en clústeres y representarlos con un pin de punto medio.
2

Aquí hay un fragmento de código que toma las coordenadas de una MKAnnotation, lo convierte en un CGPoint relativo al MKMapView y registra cuál es la vista subyacente en ese CGPoint.

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

Ponlo dentro de un bucle que itera por todos tus contactos. Si la vista subyacente es otra instancia de MKAnnotation, oculte ese pin.

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

Para que esto funcione correctamente, es necesario el pinsArray a ser ordenado de manera que el índice 0 es el pasador más delantera.

+0

enfoque interesante, aunque no perfecto – chatur

6

Si una biblioteca comercial de terceros es una opción, consulte Superpin (la licencia cuesta $ 199). Es un Marco de iOS que internamente utiliza cuatrienares para el almacenamiento de anotaciones y realiza clustering basado en grillas. El algoritmo es bastante rápido, la aplicación de muestra incluida muestra los aeropuertos del mundo (más de 30k + anotaciones) y funciona sin problemas en un iPhone 3G.

También es posible que desee comprobar http://revolver.be/blog/mapkit-clustering-with-ios/, otra solución prefabricada, que es gratuita para proyectos no comerciales.

responsabilidad: yo soy uno de los desarrolladores Superpin

+0

Descubrí que era bastante fácil integrar el proyecto de revólver de código abierto en mi propia aplicación. Gracias esad! –

0

tarde a la fiesta, lo sé, pero es posible encontrar esta rutina útil. Viene de this file, que es parte de a FOSS project.

/**************************************************************//** 
\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; 
} 

Puede verlo en acción en the released version de la aplicación.

Las reuniones en las proximidades se agrupan en anotaciones rojas, que abren una lista.

Cuestiones relacionadas