Authored by Thomas Rasch

Merge branch 'develop' into release

Subproject commit c18eac424c70ac8ce468e627a1cbde835061f44b
Subproject commit 0cfca849943c6d109934c9d708d0942a8708cb99
... ...
... ... @@ -135,7 +135,9 @@
return nil;
}
[[queue database] setShouldCacheStatements:YES];
[queue inDatabase:^(FMDatabase *db) {
[db setShouldCacheStatements:YES];
}];
RMLog(@"Opening db map source %@", path);
... ...
... ... @@ -90,13 +90,15 @@
- (void)configureDBForFirstUse
{
[[[queue database] executeQuery:@"PRAGMA synchronous=OFF"] close];
[[[queue database] executeQuery:@"PRAGMA journal_mode=OFF"] close];
[[[queue database] executeQuery:@"PRAGMA cache-size=100"] close];
[[[queue database] executeQuery:@"PRAGMA count_changes=OFF"] close];
[[queue database] executeUpdate:@"CREATE TABLE IF NOT EXISTS ZCACHE (tile_hash INTEGER NOT NULL, cache_key VARCHAR(25) NOT NULL, last_used DOUBLE NOT NULL, data BLOB NOT NULL)"];
[[queue database] executeUpdate:@"CREATE UNIQUE INDEX IF NOT EXISTS main_index ON ZCACHE(tile_hash, cache_key)"];
[[queue database] executeUpdate:@"CREATE INDEX IF NOT EXISTS last_used_index ON ZCACHE(last_used)"];
[queue inDatabase:^(FMDatabase *db) {
[[db executeQuery:@"PRAGMA synchronous=OFF"] close];
[[db executeQuery:@"PRAGMA journal_mode=OFF"] close];
[[db executeQuery:@"PRAGMA cache-size=100"] close];
[[db executeQuery:@"PRAGMA count_changes=OFF"] close];
[db executeUpdate:@"CREATE TABLE IF NOT EXISTS ZCACHE (tile_hash INTEGER NOT NULL, cache_key VARCHAR(25) NOT NULL, last_used DOUBLE NOT NULL, data BLOB NOT NULL)"];
[db executeUpdate:@"CREATE UNIQUE INDEX IF NOT EXISTS main_index ON ZCACHE(tile_hash, cache_key)"];
[db executeUpdate:@"CREATE INDEX IF NOT EXISTS last_used_index ON ZCACHE(last_used)"];
}];
}
- (id)initWithDatabase:(NSString *)path
... ... @@ -114,9 +116,9 @@
queue = [[FMDatabaseQueue databaseQueueWithPath:path] retain];
if (!queue || ![[queue database] open])
if (!queue)
{
RMLog(@"Could not connect to database - %@", [[queue database] lastErrorMessage]);
RMLog(@"Could not connect to database");
[[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
... ... @@ -124,8 +126,10 @@
return nil;
}
[[queue database] setCrashOnErrors:TRUE];
[[queue database] setShouldCacheStatements:TRUE];
[queue inDatabase:^(FMDatabase *db) {
[db setCrashOnErrors:TRUE];
[db setShouldCacheStatements:TRUE];
}];
[self configureDBForFirstUse];
... ...
... ... @@ -127,6 +127,38 @@ RMProjectedRect RMProjectedRectZero()
return RMProjectedRectMake(0.0, 0.0, 0.0, 0.0);
}
bool RMProjectedRectIsZero(RMProjectedRect rect)
{
return (rect.origin.x == 0.0) && (rect.origin.y == 0.0) && (rect.size.width == 0.0) && (rect.size.height == 0.0);
}
#if !defined (RMMIN)
#define RMMIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#if !defined (RMMAX)
#define RMMAX(a,b) ((a) > (b) ? (a) : (b))
#endif
RMProjectedRect RMProjectedRectUnion(RMProjectedRect rect1, RMProjectedRect rect2)
{
bool rect1IsZero = RMProjectedRectIsZero(rect1);
bool rect2IsZero = RMProjectedRectIsZero(rect2);
if (rect1IsZero)
return (rect2IsZero ? RMProjectedRectZero() : rect2);
if (rect2IsZero)
return rect1;
double minX = RMMIN(rect1.origin.x, rect2.origin.x);
double minY = RMMIN(rect1.origin.y, rect2.origin.y);
double maxX = RMMAX(rect1.origin.x + rect1.size.width, rect2.origin.x + rect2.size.width);
double maxY = RMMAX(rect1.origin.y + rect2.size.height, rect2.origin.y + rect2.size.height);
return RMProjectedRectMake(minX, minY, maxX - minX, maxY - minY);
}
double RMEuclideanDistanceBetweenProjectedPoints(RMProjectedPoint point1, RMProjectedPoint point2)
{
double xd = point2.x - point1.x;
... ...
... ... @@ -69,16 +69,22 @@ RMProjectedRect RMTranslateProjectedRectBy(RMProjectedRect rect, RMProjectedSiz
/// \brief The function checks whether two passed projected points are equal.
bool RMProjectedPointEqualToProjectedPoint(RMProjectedPoint point1, RMProjectedPoint point2);
/// \brief The function returs true if the passed rects intersect each other.
bool RMProjectedRectIntersectsProjectedRect(RMProjectedRect rect1, RMProjectedRect rect2);
/// \brief The function returns true if rect1 contains rect2
bool RMProjectedRectContainsProjectedRect(RMProjectedRect rect1, RMProjectedRect rect2);
// Union of two rectangles
RMProjectedRect RMProjectedRectUnion(RMProjectedRect rect1, RMProjectedRect rect2);
RMProjectedPoint RMProjectedPointMake(double x, double y);
RMProjectedRect RMProjectedRectMake(double x, double y, double width, double height);
RMProjectedSize RMProjectedSizeMake(double width, double heigth);
RMProjectedRect RMProjectedRectZero();
bool RMProjectedRectIsZero(RMProjectedRect rect);
double RMEuclideanDistanceBetweenProjectedPoints(RMProjectedPoint point1, RMProjectedPoint point2);
... ...
... ... @@ -57,7 +57,9 @@
if ( ! queue)
return nil;
[[queue database] setShouldCacheStatements:YES];
[queue inDatabase:^(FMDatabase *db) {
[db setShouldCacheStatements:YES];
}];
return self;
}
... ...
... ... @@ -211,7 +211,11 @@
CGPoint translation = [recognizer translationInView:self];
CGPoint delta = CGPointMake(_lastTranslation.x - translation.x, _lastTranslation.y - translation.y);
_lastTranslation = translation;
[CATransaction begin];
[CATransaction setAnimationDuration:0];
[delegate mapOverlayView:self didDragAnnotation:_draggedAnnotation withDelta:delta];
[CATransaction commit];
}
else if (recognizer.state == UIGestureRecognizerStateEnded && [delegate respondsToSelector:@selector(mapOverlayView:didEndDragAnnotation:)])
{
... ...
... ... @@ -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)
... ...