views:

408

answers:

5

I'm coding a map view with around 900 annotations. Having this many annotations on a map make the performance suffer, so I'd like to reduce it to about 300 at a time. The annotations are representing shops in a country, so they tend to cluster a lot around major cities, then in small groups of 2 or 3 in smaller towns. I want to reduce the numbers so that the groups of 2 or 3 are left alone, but the numbers in the city are thinned (they're so close together that they offer no useful information).

In the image you can see that there are a couple of big groups (Tokyo, Nagoya and Osaka) which I want to thin out. But with the pins on their own or in small groups, I want to make sure they don't get filtered. Once I zoom in, I want to show the missing pins.

Does anyone know of some good code that I can use, so that points which are close together are eliminated, but ones more spread out are left alone?

alt text

+1  A: 

One approach is that before placing a new pin, check if there's another pin already placed within distance d of the new pin. If there is, don't place the new pin. You need to vary d based on the current zoom level.

You can reduce the number of pins you check against by considering only pins in a bounding box centered on the new pin. The box could be d x d degrees on a side (with d varying based on zoom level).

DyingCactus
A: 

Considering that many pins in densely-populated areas will be on the same street, you could consider making "super pins" that list the pins on a particular street, instead of on each individual address.

-S!

Stephen Furlani
+1  A: 

There is a GREAT article that you should read that talks about the exact scenario you are referencing.

http://www.drobnik.com/touch/2010/01/dr-touchs-incredible-poi-weight-loss-formula/

Cory Wiles
Thanks for the info. It's close to what I'm looking for, he groups and allows for ungrouping by touching the pin. Unfortunately it's 100 euros for the code. (@_@)
nevan
+2  A: 

Two options I can think of:

  • If you have points of interest to work with (Eg, cities), you can simply group all pins by the POI they're closest to, in lower zoom levels.
  • You can use K-means clustering to group pins into clusters and represent them with a midpoint pin.
Nick Johnson
A: 

Here's a code snippet that takes an MKAnnotation's coordinates, convert it to a CGPoint relative to the MKMapView, and logs what's the underlying view at that CGPoint.

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

Put that inside a loop that iterates through all your pins. If the underlying view is another MKAnnotation instance, then hide that pin.

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

For this to work properly, you need the pinsArray to be ordered so that index 0 is the frontmost pin.

Sam V