OCMapView 1.0
Simple and easy to use clustering mapView.
/Users/Boti/Documents/coding/iPhone Development/OCMapView+Sample/OCMapView/OCMapView.m
Go to the documentation of this file.
00001 //
00002 //  OCMapView.m
00003 //  openClusterMapView
00004 //
00005 //  Created by Botond Kis on 14.07.11.
00006 //
00007 
00008 #import "OCMapView.h"
00009 
00010 @interface OCMapView (private)
00011 - (void)initSetUp;
00012 @end
00013 
00014 @implementation OCMapView
00015 @synthesize clusteringEnabled;
00016 @synthesize annotationsToIgnore;
00017 @synthesize clusteringMethod;
00018 @synthesize clusterSize;
00019 @synthesize clusterByGroupTag;
00020 @synthesize minLongitudeDeltaToCluster;
00021 
00022 - (id)init
00023 {
00024     self = [super init];
00025     if (self) {
00026         // call acutal constructor
00027         [self initSetUp];
00028     }
00029     
00030     return self;
00031 }
00032 
00033 - (id)initWithCoder:(NSCoder *)aDecoder{
00034     self = [super initWithCoder:aDecoder];    
00035     if (self) {
00036         // call acutal constructor
00037         [self initSetUp];
00038     }
00039     return self;
00040 }
00041 
00042 - (void)initSetUp{
00043     allAnnotations = [[NSMutableSet alloc] init];
00044     annotationsToIgnore = [[NSMutableSet alloc] init];
00045     clusteringMethod = OCClusteringMethodBubble;
00046     clusterSize = 0.2;
00047     minLongitudeDeltaToCluster = 0.0;
00048     clusteringEnabled = YES;
00049     clusterByGroupTag = NO;
00050     backgroundClusterQueue = dispatch_queue_create("com.OCMapView.clustering", NULL);  
00051 }
00052 
00053 - (void)dealloc{
00054     [allAnnotations release];
00055     [annotationsToIgnore release];
00056     dispatch_release(backgroundClusterQueue);
00057     
00058     [super dealloc];
00059 }
00060 
00061 // ======================================
00062 #pragma mark MKMapView implementation
00063 
00064 - (void)addAnnotation:(id < MKAnnotation >)annotation{
00065     [allAnnotations addObject:annotation];
00066     [self doClustering];
00067 }
00068 
00069 - (void)addAnnotations:(NSArray *)annotations{
00070     [allAnnotations addObjectsFromArray:annotations];
00071     [self doClustering];
00072 }
00073 
00074 - (void)removeAnnotation:(id < MKAnnotation >)annotation{
00075     [allAnnotations removeObject:annotation];
00076     [self doClustering];
00077 }
00078 
00079 - (void)removeAnnotations:(NSArray *)annotations{
00080     [annotations retain];
00081     for (id<MKAnnotation> annotation in annotations) {
00082         [allAnnotations removeObject:annotation];
00083     }
00084     [annotations release];
00085     [self doClustering];
00086 }
00087 
00088 
00089 // ======================================
00090 #pragma mark - Properties
00091 //
00092 // Returns, like the original method,
00093 // all annotations in the map unclustered.
00094 - (NSArray *)annotations{
00095     return [allAnnotations allObjects];
00096 }
00097 
00098 //
00099 // Returns all annotations which are actually displayed on the map. (clusters)
00100 - (NSArray *)displayedAnnotations{
00101     return super.annotations;    
00102 }
00103 
00104 //
00105 // enable or disable clustering
00106 - (void)setClusteringEnabled:(BOOL)enabled{
00107     clusteringEnabled = enabled;
00108     [self doClustering];
00109 }
00110 
00111 // ======================================
00112 #pragma mark - Clustering
00113 
00114 - (void)doClustering{
00115     
00116     // Remove the annotation which should be ignored
00117     NSMutableArray *bufferArray = [[NSMutableArray alloc] initWithArray:[allAnnotations allObjects]];
00118     [bufferArray removeObjectsInArray:[annotationsToIgnore allObjects]];
00119     NSMutableArray *annotationsToCluster = [[NSMutableArray alloc] initWithArray:[self filterAnnotationsForVisibleMap:bufferArray]];
00120     [bufferArray release];
00121     
00122     //calculate cluster radius
00123     CLLocationDistance clusterRadius = self.region.span.longitudeDelta * clusterSize;
00124     
00125     // Do clustering
00126     NSArray *clusteredAnnotations;
00127     
00128     // Check if clustering is enabled and map is above the minZoom
00129     if (clusteringEnabled && (self.region.span.longitudeDelta > minLongitudeDeltaToCluster)) {
00130         
00131         // switch to selected algoritm
00132         switch (clusteringMethod) {
00133             case OCClusteringMethodBubble:{
00134                 clusteredAnnotations = [[NSArray alloc] initWithArray:[OCAlgorithms bubbleClusteringWithAnnotations:annotationsToCluster andClusterRadius:clusterRadius grouped:self.clusterByGroupTag]];
00135                 break;
00136             }
00137             case OCClusteringMethodGrid:{
00138                 clusteredAnnotations =[[NSArray alloc] initWithArray:[OCAlgorithms gridClusteringWithAnnotations:annotationsToCluster andClusterRect:MKCoordinateSpanMake(clusterRadius, clusterRadius)  grouped:self.clusterByGroupTag]];
00139                 break;
00140             }
00141             default:{
00142                 clusteredAnnotations = [annotationsToCluster retain];
00143                 break;
00144             }
00145         }
00146     }
00147     // pass through without when not
00148     else{
00149         clusteredAnnotations = [annotationsToCluster retain];
00150     }
00151     
00152     // Clear map but leave Userlcoation
00153     NSMutableArray *annotationsToRemove = [[NSMutableArray alloc] initWithArray:self.displayedAnnotations];
00154     [annotationsToRemove removeObject:self.userLocation];
00155     
00156     // add clustered and ignored annotations to map
00157     [super addAnnotations: clusteredAnnotations];
00158     [super addAnnotations: [annotationsToIgnore allObjects]];
00159     
00160     // fix for flickering
00161     [annotationsToRemove removeObjectsInArray: clusteredAnnotations];
00162     [super removeAnnotations:annotationsToRemove];
00163     
00164     // memory
00165     [clusteredAnnotations release];
00166     [annotationsToCluster release];
00167     [annotationsToRemove release];
00168 }
00169 
00170 // ======================================
00171 #pragma mark - Helpers
00172 
00173 - (NSArray *)filterAnnotationsForVisibleMap:(NSArray *)annotationsToFilter{
00174     // return array
00175     NSMutableArray *filteredAnnotations = [[NSMutableArray alloc] initWithCapacity:[annotationsToFilter count]];
00176     
00177     // border calculation
00178     CLLocationDistance a = self.region.span.latitudeDelta/2.0;
00179     CLLocationDistance b = self.region.span.longitudeDelta /2.0;
00180     CLLocationDistance radius = sqrt(a*a + b*b);
00181     
00182     for (id<MKAnnotation> annotation in annotationsToFilter) {
00183         // if annotation is not inside the coordinates, kick it
00184         if (isLocationNearToOtherLocation(annotation.coordinate, self.centerCoordinate, radius)) {
00185             [filteredAnnotations addObject:annotation];
00186         }
00187     }
00188     
00189     return [filteredAnnotations autorelease];
00190 }
00191 
00192 @end
 All Data Structures Files Functions Variables Enumerations Enumerator Properties