Authored by Thomas Rasch

o Some performance improvements for annotations and clusters

... ... @@ -80,7 +80,7 @@ typedef enum {
double metersPerPixel;
BOOL adjustTilesForRetinaDisplay;
NSMutableArray *annotations;
NSMutableSet *annotations;
NSMutableSet *visibleAnnotations;
RMQuadTree *quadTree;
BOOL enableClustering, positionClusterMarkersAtTheGravityCenter;
... ...
... ... @@ -48,7 +48,7 @@
#pragma mark --- begin constants ----
#define kiPhoneMilimeteresPerPixel .1543
#define kZoomRectPixelBuffer 100.0
#define kZoomRectPixelBuffer 150.0
#define kDefaultInitialLatitude 47.56
#define kDefaultInitialLongitude 10.22
... ... @@ -143,7 +143,7 @@
boundingMask = RMMapMinWidthBound;
adjustTilesForRetinaDisplay = NO;
annotations = [NSMutableArray new];
annotations = [NSMutableSet new];
visibleAnnotations = [NSMutableSet new];
[self setQuadTree:[[[RMQuadTree alloc] initWithMapView:self] autorelease]];
enableClustering = positionClusterMarkersAtTheGravityCenter = NO;
... ... @@ -1673,7 +1673,7 @@
- (NSArray *)annotations
{
return [NSArray arrayWithArray:annotations];
return [annotations allObjects];
}
- (void)addAnnotation:(RMAnnotation *)annotation
... ... @@ -1709,11 +1709,8 @@
{
@synchronized (annotations)
{
for (RMAnnotation *annotation in newAnnotations)
{
[annotations addObject:annotation];
[self.quadTree addAnnotation:annotation];
}
[annotations addObjectsFromArray:newAnnotations];
[self.quadTree addAnnotations:newAnnotations];
}
[self correctPositionOfAllAnnotationsIncludingInvisibles:YES wasZoom:NO];
... ...
... ... @@ -27,8 +27,10 @@ typedef enum {
RMQuadTreeNode *parentNode, *northWest, *northEast, *southWest, *southEast;
RMQuadTreeNodeType nodeType;
RMMapView *mapView;
RMAnnotation *cachedClusterAnnotation;
NSArray *cachedClusterEnclosedAnnotations;
NSMutableArray *cachedEnclosedAnnotations, *cachedUnclusteredAnnotations;
}
@property (nonatomic, readonly) NSArray *annotations;
... ... @@ -68,6 +70,7 @@ typedef enum {
- (id)initWithMapView:(RMMapView *)aMapView;
- (void)addAnnotation:(RMAnnotation *)annotation;
- (void)addAnnotations:(NSArray *)annotations;
- (void)removeAnnotation:(RMAnnotation *)annotation;
- (void)removeAllObjects;
... ...
... ... @@ -29,6 +29,8 @@
- (void)removeUpwardsAllCachedClusterAnnotations;
- (void)precreateQuadTreeInBounds:(RMProjectedRect)quadTreeBounds withDepth:(NSUInteger)quadTreeDepth;
@end
@implementation RMQuadTreeNode
... ... @@ -51,6 +53,7 @@
boundingBox = aBoundingBox;
cachedClusterAnnotation = nil;
cachedClusterEnclosedAnnotations = nil;
cachedEnclosedAnnotations = cachedUnclusteredAnnotations = nil;
double halfWidth = boundingBox.size.width / 2.0, halfHeight = boundingBox.size.height / 2.0;
northWestBoundingBox = RMProjectedRectMake(boundingBox.origin.x, boundingBox.origin.y + halfHeight, halfWidth, halfHeight);
... ... @@ -82,6 +85,8 @@
}
[annotations release]; annotations = nil;
[cachedEnclosedAnnotations release]; cachedEnclosedAnnotations = nil;
[cachedUnclusteredAnnotations release]; cachedUnclusteredAnnotations = nil;
[northWest release]; northWest = nil;
[northEast release]; northEast = nil;
... ... @@ -148,6 +153,70 @@
}
}
- (void)precreateQuadTreeInBounds:(RMProjectedRect)quadTreeBounds withDepth:(NSUInteger)quadTreeDepth
{
if (quadTreeDepth == 0 || boundingBox.size.width < (kMinimumQuadTreeElementWidth * 2.0))
return;
// RMLog(@"node in {%.0f,%.0f},{%.0f,%.0f} depth %d", boundingBox.origin.x, boundingBox.origin.y, boundingBox.size.width, boundingBox.size.height, quadTreeDepth);
@synchronized (cachedClusterAnnotation)
{
[cachedClusterAnnotation release]; cachedClusterAnnotation = nil;
[cachedClusterEnclosedAnnotations release]; cachedClusterEnclosedAnnotations = nil;
}
if (RMProjectedRectIntersectsProjectedRect(quadTreeBounds, northWestBoundingBox))
{
if (!northWest)
northWest = [[RMQuadTreeNode alloc] initWithMapView:mapView forParent:self inBoundingBox:northWestBoundingBox];
[northWest precreateQuadTreeInBounds:quadTreeBounds withDepth:quadTreeDepth-1];
}
if (RMProjectedRectIntersectsProjectedRect(quadTreeBounds, northEastBoundingBox))
{
if (!northEast)
northEast = [[RMQuadTreeNode alloc] initWithMapView:mapView forParent:self inBoundingBox:northEastBoundingBox];
[northEast precreateQuadTreeInBounds:quadTreeBounds withDepth:quadTreeDepth-1];
}
if (RMProjectedRectIntersectsProjectedRect(quadTreeBounds, southWestBoundingBox))
{
if (!southWest)
southWest = [[RMQuadTreeNode alloc] initWithMapView:mapView forParent:self inBoundingBox:southWestBoundingBox];
[southWest precreateQuadTreeInBounds:quadTreeBounds withDepth:quadTreeDepth-1];
}
if (RMProjectedRectIntersectsProjectedRect(quadTreeBounds, southEastBoundingBox))
{
if (!southEast)
southEast = [[RMQuadTreeNode alloc] initWithMapView:mapView forParent:self inBoundingBox:southEastBoundingBox];
[southEast precreateQuadTreeInBounds:quadTreeBounds withDepth:quadTreeDepth-1];
}
if (nodeType == nodeTypeLeaf && [annotations count])
{
NSArray *immutableAnnotations = nil;
@synchronized (annotations)
{
immutableAnnotations = [NSArray arrayWithArray:annotations];
[annotations removeAllObjects];
}
for (RMAnnotation *annotationToMove in immutableAnnotations)
{
[self addAnnotationToChildNodes:annotationToMove];
}
}
nodeType = nodeTypeNode;
}
- (void)addAnnotation:(RMAnnotation *)annotation
{
if (nodeType == nodeTypeLeaf)
... ... @@ -229,45 +298,45 @@
- (NSUInteger)countEnclosedAnnotations
{
NSUInteger count = [annotations count];
count += [northWest countEnclosedAnnotations];
count += [northEast countEnclosedAnnotations];
count += [southWest countEnclosedAnnotations];
count += [southEast countEnclosedAnnotations];
return count;
return [self.enclosedAnnotations count];
}
- (NSArray *)enclosedAnnotations
{
NSMutableArray *enclosedAnnotations = [NSMutableArray arrayWithArray:self.annotations];
if (northWest) [enclosedAnnotations addObjectsFromArray:northWest.enclosedAnnotations];
if (northEast) [enclosedAnnotations addObjectsFromArray:northEast.enclosedAnnotations];
if (southWest) [enclosedAnnotations addObjectsFromArray:southWest.enclosedAnnotations];
if (southEast) [enclosedAnnotations addObjectsFromArray:southEast.enclosedAnnotations];
if (!cachedEnclosedAnnotations)
{
cachedEnclosedAnnotations = [[NSMutableArray alloc] initWithArray:self.annotations];
if (northWest) [cachedEnclosedAnnotations addObjectsFromArray:northWest.enclosedAnnotations];
if (northEast) [cachedEnclosedAnnotations addObjectsFromArray:northEast.enclosedAnnotations];
if (southWest) [cachedEnclosedAnnotations addObjectsFromArray:southWest.enclosedAnnotations];
if (southEast) [cachedEnclosedAnnotations addObjectsFromArray:southEast.enclosedAnnotations];
}
return enclosedAnnotations;
return cachedEnclosedAnnotations;
}
- (NSArray *)unclusteredAnnotations
{
NSMutableArray *unclusteredAnnotations = [NSMutableArray array];
@synchronized (annotations)
if (!cachedUnclusteredAnnotations)
{
for (RMAnnotation *annotation in annotations)
cachedUnclusteredAnnotations = [NSMutableArray new];
@synchronized (annotations)
{
if (!annotation.clusteringEnabled)
[unclusteredAnnotations addObject:annotation];
for (RMAnnotation *annotation in annotations)
{
if (!annotation.clusteringEnabled)
[cachedUnclusteredAnnotations addObject:annotation];
}
}
}
if (northWest) [unclusteredAnnotations addObjectsFromArray:[northWest unclusteredAnnotations]];
if (northEast) [unclusteredAnnotations addObjectsFromArray:[northEast unclusteredAnnotations]];
if (southWest) [unclusteredAnnotations addObjectsFromArray:[southWest unclusteredAnnotations]];
if (southEast) [unclusteredAnnotations addObjectsFromArray:[southEast unclusteredAnnotations]];
if (northWest) [cachedUnclusteredAnnotations addObjectsFromArray:[northWest unclusteredAnnotations]];
if (northEast) [cachedUnclusteredAnnotations addObjectsFromArray:[northEast unclusteredAnnotations]];
if (southWest) [cachedUnclusteredAnnotations addObjectsFromArray:[southWest unclusteredAnnotations]];
if (southEast) [cachedUnclusteredAnnotations addObjectsFromArray:[southEast unclusteredAnnotations]];
}
return unclusteredAnnotations;
return cachedUnclusteredAnnotations;
}
- (RMAnnotation *)clusterAnnotation
... ... @@ -466,6 +535,9 @@
[cachedClusterAnnotation release]; cachedClusterAnnotation = nil;
[cachedClusterEnclosedAnnotations release]; cachedClusterEnclosedAnnotations = nil;
}
[cachedEnclosedAnnotations release]; cachedEnclosedAnnotations = nil;
[cachedUnclusteredAnnotations release]; cachedUnclusteredAnnotations = nil;
}
@end
... ... @@ -501,6 +573,20 @@
}
}
- (void)addAnnotations:(NSArray *)annotations
{
// RMLog(@"Prepare tree");
// [rootNode precreateQuadTreeInBounds:[[RMProjection googleProjection] planetBounds] withDepth:5];
@synchronized (self)
{
for (RMAnnotation *annotation in annotations)
{
[rootNode addAnnotation:annotation];
}
}
}
- (void)removeAnnotation:(RMAnnotation *)annotation
{
@synchronized (self)
... ...