Authored by Thomas Rasch

o Merge local changes

... ... @@ -171,7 +171,7 @@
return NO;
}
- (void) compainAboutInUse {
- (void) complainAboutInUse {
NSLog(@"The FMDatabase %@ is currently in use.", self);
if (crashOnErrors) {
... ... @@ -196,7 +196,7 @@
- (sqlite_int64) lastInsertRowId {
if (inUse) {
[self compainAboutInUse];
[self complainAboutInUse];
return NO;
}
[self setInUse:YES];
... ... @@ -216,7 +216,7 @@
// FIXME - someday check the return codes on these binds.
else if ([obj isKindOfClass:[NSData class]]) {
sqlite3_bind_blob(pStmt, idx, [obj bytes], (int)[obj length], SQLITE_STATIC);
sqlite3_bind_blob(pStmt, idx, [obj bytes], (int)[(NSData *)obj length], SQLITE_STATIC);
}
else if ([obj isKindOfClass:[NSDate class]]) {
sqlite3_bind_double(pStmt, idx, [obj timeIntervalSince1970]);
... ... @@ -253,7 +253,7 @@
- (id) executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orVAList:(va_list)args {
if (inUse) {
[self compainAboutInUse];
[self complainAboutInUse];
return nil;
}
... ... @@ -387,7 +387,7 @@
- (BOOL) executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray*)arrayArgs orVAList:(va_list)args {
if (inUse) {
[self compainAboutInUse];
[self complainAboutInUse];
return NO;
}
... ...
... ... @@ -38,6 +38,8 @@
RMTileCache *cache;
}
@property (nonatomic, readonly) RMTileCache *cache;
- (id) initWithSource: (id<RMTileSource>) source;
- (void) didReceiveMemoryWarning;
... ...
... ... @@ -30,6 +30,8 @@
@implementation RMCachedTileSource
@synthesize cache;
- (id) initWithSource: (id<RMTileSource>) _source
{
if ([_source isKindOfClass:[RMCachedTileSource class]])
... ...
... ... @@ -107,12 +107,10 @@
self = [super init];
if (self != nil) {
// open the db
NSString* fullPath = [[NSBundle mainBundle] pathForResource:path ofType:nil];
NSLog(@"Trying to Open db map source %@", fullPath);
db = [[FMDatabase alloc] initWithPath:fullPath];
if ([db open]) {
db = [[FMDatabase alloc] initWithPath:path];
if ([db openWithFlags:SQLITE_OPEN_READONLY]) {
RMLog(@"Opening db map source %@", path);
// get the tile side length
tileSideLength = [self getPreferenceAsInt:kTileSideLengthKey];
... ... @@ -124,12 +122,12 @@
topLeft.latitude = [self getPreferenceAsFloat:kCoverageTopLeftLatitudeKey];
topLeft.longitude = [self getPreferenceAsFloat:kCoverageTopLeftLongitudeKey];
bottomRight.latitude = [self getPreferenceAsFloat:kCoverageBottomRightLatitudeKey];
bottomRight.longitude = [self getPreferenceAsFloat:kCoverageBottomRightLatitudeKey];
bottomRight.longitude = [self getPreferenceAsFloat:kCoverageBottomRightLongitudeKey];
center.latitude = [self getPreferenceAsFloat:kCoverageCenterLatitudeKey];
center.longitude = [self getPreferenceAsFloat:kCoverageCenterLongitudeKey];
RMLog(@"Tile size: %d pixel", tileSideLength);
RMLog(@"Supported zoom range: %d - %d", minZoom, maxZoom);
RMLog(@"Supported zoom range: %.0f - %.0f", minZoom, maxZoom);
RMLog(@"Coverage area: (%2.6f,%2.6f) x (%2.6f,%2.6f)",
topLeft.latitude,
topLeft.longitude,
... ... @@ -180,19 +178,14 @@
return maxZoom;
}
-(void) setMinZoom:(NSUInteger)aMinZoom
{
[tileProjection setMinZoom:aMinZoom];
}
-(void) setMaxZoom:(NSUInteger)aMaxZoom
-(void) setMinZoom:(NSUInteger) aMinZoom
{
[tileProjection setMaxZoom:aMaxZoom];
minZoom = aMinZoom;
}
-(RMSphericalTrapezium) latitudeLongitudeBoundingBox;
-(void) setMaxZoom:(NSUInteger) aMaxZoom
{
return kDefaultLatLonBoundingBox;
maxZoom = aMaxZoom;
}
-(NSString*) tileURL: (RMTile) tile {
... ... @@ -220,6 +213,21 @@
return [RMProjection googleProjection];
}
-(RMSphericalTrapezium) latitudeLongitudeBoundingBox
{
CLLocationCoordinate2D southwest, northeast;
southwest.latitude = bottomRight.latitude;
southwest.longitude = topLeft.longitude;
northeast.latitude = topLeft.latitude;
northeast.longitude = bottomRight.longitude;
RMSphericalTrapezium bbox;
bbox.southwest = southwest;
bbox.northeast = northeast;
return bbox;
}
-(void) didReceiveMemoryWarning {
LogMethod();
}
... ...
... ... @@ -42,14 +42,16 @@
if (self != nil) {
// get the unique key for the tile
NSNumber* key = [NSNumber numberWithLongLong:RMTileKey(_tile)];
RMLog(@"fetching tile %@ (y:%d, x:%d)@%d", key, _tile.y, _tile.x, _tile.zoom);
// RMLog(@"fetching tile %@ (y:%d, x:%d)@%d", key, _tile.y, _tile.x, _tile.zoom);
// fetch the image from the db
FMResultSet* rs = [db executeQuery:@"select image from tiles where tilekey = ?", key];
FMDBErrorCheck(db);
if ([rs next]) {
[self updateImageUsingImage:[[[UIImage alloc] initWithData:[rs dataForColumn:@"image"]] autorelease]];
}
} else {
[self updateImageUsingImage:[UIImage imageNamed:@"nodata.png"]];
}
[rs close];
}
return self;
... ...
... ... @@ -48,6 +48,4 @@
-(void) setCapacity: (NSUInteger) theCapacity;
-(void) setMinimalPurge: (NSUInteger) thePurgeMinimum;
-(void) purgeTilesFromBefore: (NSDate*) date;
@end
... ...
... ... @@ -70,6 +70,10 @@
self.databasePath = path;
dao = [[RMTileCacheDAO alloc] initWithDatabase:path];
if (!dao) {
[[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
dao = [[RMTileCacheDAO alloc] initWithDatabase:path];
}
if (dao == nil)
return nil;
... ... @@ -79,7 +83,7 @@
-(id) initWithTileSource: (id<RMTileSource>) source usingCacheDir: (BOOL) useCacheDir
{
return [self initWithDatabase:[RMDatabaseCache dbPathForTileSource:source usingCacheDir: useCacheDir]];
return [self initWithDatabase:[RMDatabaseCache dbPathForTileSource:source usingCacheDir:useCacheDir]];
}
-(void) dealloc
... ... @@ -119,14 +123,11 @@
/// \bug magic string literals
RMTileImage *image = (RMTileImage*)[notification object];
@synchronized (self) {
if (capacity != 0) {
NSUInteger tilesInDb = [dao count];
if (capacity <= tilesInDb) {
[dao purgeTiles: MAX(minimalPurge, 1+tilesInDb-capacity)];
}
}
if (capacity != 0) {
NSUInteger tilesInDb = [dao count];
if (capacity <= tilesInDb) {
[dao purgeTiles: MAX(minimalPurge, 1+tilesInDb-capacity)];
}
[dao addData:data LastUsed:[image lastUsedTime] ForTile:RMTileKey([image tile])];
}
... ... @@ -145,45 +146,27 @@
NSData *data = nil;
@synchronized (self) {
data = [dao dataForTile:RMTileKey(tile)];
if (data == nil)
return nil;
data = [dao dataForTile:RMTileKey(tile)];
if (data == nil)
return nil;
if (capacity != 0 && purgeStrategy == RMCachePurgeStrategyLRU) {
[dao touchTile: RMTileKey(tile) withDate: [NSDate date]];
}
}
if (capacity != 0 && purgeStrategy == RMCachePurgeStrategyLRU) {
[dao touchTile: RMTileKey(tile) withDate: [NSDate date]];
}
RMTileImage *image = [RMTileImage imageForTile:tile withData:data];
// RMLog(@"DB cache hit for tile %d %d %d", tile.x, tile.y, tile.zoom);
return image;
}
-(void) purgeTilesFromBefore: (NSDate*) date
{
@synchronized(self)
{
[dao purgeTilesFromBefore:date];
}
}
-(void)didReceiveMemoryWarning
{
@synchronized(self)
{
[dao didReceiveMemoryWarning];
}
[dao didReceiveMemoryWarning];
}
-(void) removeAllCachedImages
{
@synchronized(self)
{
[dao removeAllCachedImages];
}
[dao removeAllCachedImages];
}
@end
... ...
... ... @@ -25,6 +25,9 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef _FOUNDATION_H_
#define _FOUNDATION_H_
/*! \struct RMProjectedPoint
\brief coordinates, in projected meters, paralleling CGPoint */
typedef struct {
... ... @@ -52,3 +55,4 @@ RMProjectedRect RMTranslateProjectedRectBy (RMProjectedRect rect, RMProjected
RMProjectedPoint RMMakeProjectedPoint (double easting, double northing);
RMProjectedRect RMMakeProjectedRect (double easting, double northing, double width, double height);
#endif
... ...
... ... @@ -116,6 +116,7 @@ enum {
float maxZoom;
float screenScale;
RMProjectedRect tileSourceProjectedBounds;
id<RMTilesUpdateDelegate> tilesUpdateDelegate;
}
... ... @@ -129,7 +130,8 @@ enum {
/// zoom level is clamped to range (minZoom, maxZoom)
@property (readwrite) float zoom;
@property (nonatomic, readwrite) float minZoom, maxZoom;
@property (nonatomic, readwrite) float minZoom;
@property (nonatomic, readwrite) float maxZoom;
@property (nonatomic, assign) float screenScale;
... ... @@ -182,6 +184,8 @@ enum {
- (void)handleMemoryWarningNotification:(NSNotification *)notification;
- (void)didReceiveMemoryWarning;
- (BOOL) tileSourceBoundsContainProjectedPoint:(RMProjectedPoint) point;
- (void)moveToLatLong: (CLLocationCoordinate2D)latlong;
- (void)moveToProjectedPoint: (RMProjectedPoint)aPoint;
... ... @@ -223,6 +227,7 @@ enum {
- (RMSphericalTrapezium) latitudeLongitudeBoundingBoxForScreen;
/// returns the smallest bounding box containing a rectangular region of the screen
- (RMSphericalTrapezium) latitudeLongitudeBoundingBoxFor:(CGRect) rect;
- (BOOL) projectedBounds:(RMProjectedRect)bounds containsPoint:(RMProjectedPoint)point;
- (void)setRotation:(float)angle;
... ...
... ... @@ -65,6 +65,7 @@
@synthesize maxZoom;
@synthesize screenScale;
@synthesize markerManager;
@synthesize imagesOnScreen;
#pragma mark --- begin constants ----
#define kZoomAnimationStepTime 0.03f
... ... @@ -121,7 +122,7 @@
return nil;
NSAssert1([newView isKindOfClass:[RMMapView class]], @"view %@ must be a subclass of RMMapView", newView);
[(RMMapView *)newView setContents:self];
// [(RMMapView *)newView setContents:self];
tileSource = nil;
projection = nil;
... ... @@ -141,10 +142,7 @@
mercatorToScreenProjection = [[RMMercatorToScreenProjection alloc] initFromProjection:[newTilesource projection] ToScreenBounds:[newView bounds]];
layer = [[newView layer] retain];
[self setMinZoom:minZoomLevel];
[self setMaxZoom:maxZoomLevel];
[self setTileSource:newTilesource];
[self setRenderer: [[[RMCoreAnimationRenderer alloc] initWithContent:self] autorelease]];
... ... @@ -154,6 +152,8 @@
tileLoader = [[RMTileLoader alloc] initWithContent:self];
[tileLoader setSuppressLoading:YES];
[self setMinZoom:minZoomLevel];
[self setMaxZoom:maxZoomLevel];
[self setZoom:initialZoomLevel];
[self moveToLatLong:initialCenter];
... ... @@ -178,7 +178,7 @@
object:nil];
RMLog(@"Map contents initialised. view: %@ tileSource %@ renderer %@", newView, tileSource, renderer);
RMLog(@"Map contents initialised. view: %@ tileSource %@ renderer %@ minZoom:%.0f maxZoom:%.0f", newView, tileSource, renderer, [self minZoom], [self maxZoom]);
return self;
}
... ... @@ -312,6 +312,87 @@
[tileSource didReceiveMemoryWarning];
}
#pragma mark Tile Source Bounds
- (BOOL) projectedBounds:(RMProjectedRect)bounds containsPoint:(RMProjectedPoint)point {
// NSLog(@"%f %f %f %f point %f %f", bounds.origin.easting, bounds.origin.northing,
// bounds.size.width, bounds.size.height, point.easting, point.northing);
if (bounds.origin.easting > point.easting ||
bounds.origin.easting + bounds.size.width < point.easting ||
bounds.origin.northing > point.northing ||
bounds.origin.northing + bounds.size.height < point.northing) {
return NO;
}
return YES;
}
- (RMProjectedRect) projectedRectFromLatLonBounds:(RMSphericalTrapezium) trap {
// RMLog(@"southwest={%f,%f}, northeast={%f,%f}", trap.southwest.longitude, trap.southwest.latitude, trap.northeast.longitude, trap.northeast.latitude);
CLLocationCoordinate2D ne = trap.northeast;
CLLocationCoordinate2D sw = trap.southwest;
float pixelBuffer = kZoomRectPixelBuffer;
CLLocationCoordinate2D midpoint = {
.latitude = (ne.latitude + sw.latitude) / 2,
.longitude = (ne.longitude + sw.longitude) / 2
};
RMProjectedPoint myOrigin = [projection latLongToPoint:midpoint];
RMProjectedPoint nePoint = [projection latLongToPoint:ne];
RMProjectedPoint swPoint = [projection latLongToPoint:sw];
RMProjectedPoint myPoint = {.easting = nePoint.easting - swPoint.easting, .northing = nePoint.northing - swPoint.northing};
//Create the new zoom layout
RMProjectedRect zoomRect;
//Default is with scale = 2.0 mercators/pixel
zoomRect.size.width = [self screenBounds].size.width * 2.0;
zoomRect.size.height = [self screenBounds].size.height * 2.0;
if((myPoint.easting / ([self screenBounds].size.width)) < (myPoint.northing / ([self screenBounds].size.height)))
{
if((myPoint.northing / ([self screenBounds].size.height - pixelBuffer)) > 1)
{
zoomRect.size.width = [self screenBounds].size.width * (myPoint.northing / ([self screenBounds].size.height - pixelBuffer));
zoomRect.size.height = [self screenBounds].size.height * (myPoint.northing / ([self screenBounds].size.height - pixelBuffer));
}
}
else
{
if((myPoint.easting / ([self screenBounds].size.width - pixelBuffer)) > 1)
{
zoomRect.size.width = [self screenBounds].size.width * (myPoint.easting / ([self screenBounds].size.width - pixelBuffer));
zoomRect.size.height = [self screenBounds].size.height * (myPoint.easting / ([self screenBounds].size.width - pixelBuffer));
}
}
myOrigin.easting = myOrigin.easting - (zoomRect.size.width / 2);
myOrigin.northing = myOrigin.northing - (zoomRect.size.height / 2);
RMLog(@"Origin is calculated at: %f, %f", [projection pointToLatLong:myOrigin].latitude, [projection pointToLatLong:myOrigin].longitude);
/*It gets all messed up if our origin is lower than the lowest place on the map, so we check.
if(myOrigin.northing < -19971868.880409)
{
myOrigin.northing = -19971868.880409;
}*/
zoomRect.origin = myOrigin;
// RMLog(@"Origin: x=%f, y=%f, w=%f, h=%f", zoomRect.origin.easting, zoomRect.origin.northing, zoomRect.size.width, zoomRect.size.height);
return zoomRect;
}
- (BOOL) tileSourceBoundsContainProjectedPoint:(RMProjectedPoint) point {
RMSphericalTrapezium bounds = [self.tileSource latitudeLongitudeBoundingBox];
if (bounds.northeast.latitude == 90 && bounds.northeast.longitude == 180 &&
bounds.southwest.latitude == -90 && bounds.southwest.longitude == -180) {
return YES;
}
// RMLog(@"tileSourceProjectedBounds: x=%f, y=%f, w=%f, h=%f, point: x=%f, y=%f, isInside: %d", tileSourceProjectedBounds.origin.easting, tileSourceProjectedBounds.origin.northing, tileSourceProjectedBounds.size.width, tileSourceProjectedBounds.size.height, point.easting, point.northing, [self projectedBounds:tileSourceProjectedBounds containsPoint:point]);
return [self projectedBounds:tileSourceProjectedBounds containsPoint:point];
}
- (BOOL) tileSourceBoundsContainScreenPoint:(CGPoint) point {
RMProjectedPoint projPoint = [mercatorToScreenProjection projectScreenPointToXY:point];
return [self tileSourceBoundsContainProjectedPoint:projPoint];
}
#pragma mark Forwarded Events
... ... @@ -320,17 +401,30 @@
RMProjectedPoint aPoint = [[self projection] latLongToPoint:latlong];
[self moveToProjectedPoint: aPoint];
}
- (void)moveToProjectedPoint: (RMProjectedPoint)aPoint
{
if (![self tileSourceBoundsContainProjectedPoint:aPoint]) {
return;
}
[mercatorToScreenProjection setProjectedCenter:aPoint];
[overlay correctPositionOfAllSublayers];
[tileLoader reload];
[renderer setNeedsDisplay];
[overlay setNeedsDisplay];
[overlay setNeedsDisplay];
}
- (void)moveBy: (CGSize) delta
{
RMProjectedPoint projCenter = [mercatorToScreenProjection projectedCenter];
RMProjectedSize XYDelta = [mercatorToScreenProjection projectScreenSizeToXY:delta];
projCenter.easting = projCenter.easting - XYDelta.width;
projCenter.northing = projCenter.northing - XYDelta.height;
if (![self tileSourceBoundsContainProjectedPoint:projCenter]) {
return;
}
[mercatorToScreenProjection moveScreenBy:delta];
[imagesOnScreen moveBy:delta];
[tileLoader moveBy:delta];
... ... @@ -425,6 +519,8 @@
/// \bug this is a no-op, not a clamp, if new zoom would be outside of minzoom/maxzoom range
- (void)zoomByFactor: (float) zoomFactor near:(CGPoint) pivot
{
if (![self tileSourceBoundsContainScreenPoint:pivot]) return;
//[self zoomByFactor:zoomFactor near:pivot animated:NO];
zoomFactor = [self adjustZoomForBoundingMask:zoomFactor];
... ... @@ -440,6 +536,7 @@
[imagesOnScreen zoomByFactor:zoomFactor near:pivot];
[tileLoader zoomByFactor:zoomFactor near:pivot];
[overlay zoomByFactor:zoomFactor near:pivot];
[overlay correctPositionOfAllSublayers];
[renderer setNeedsDisplay];
}
}
... ... @@ -472,6 +569,8 @@
- (void)zoomByFactor: (float) zoomFactor near:(CGPoint) pivot animated:(BOOL) animated withCallback:(id<RMMapContentsAnimationCallback>)callback
{
if (![self tileSourceBoundsContainScreenPoint:pivot]) return;
zoomFactor = [self adjustZoomForBoundingMask:zoomFactor];
float zoomDelta = log2f(zoomFactor);
float targetZoom = zoomDelta + [self zoom];
... ... @@ -519,6 +618,7 @@
[imagesOnScreen zoomByFactor:zoomFactor near:pivot];
[tileLoader zoomByFactor:zoomFactor near:pivot];
[overlay zoomByFactor:zoomFactor near:pivot];
[overlay correctPositionOfAllSublayers];
[renderer setNeedsDisplay];
}
}
... ... @@ -613,28 +713,45 @@
#pragma mark Properties
static NSMutableDictionary *cachedTilesources = nil;
- (void) setTileSource: (id<RMTileSource>)newTileSource
{
if (tileSource == newTileSource)
return;
RMCachedTileSource *newCachedTileSource = [RMCachedTileSource cachedTileSourceWithSource:newTileSource];
newCachedTileSource = [newCachedTileSource retain];
[tileSource release];
tileSource = newCachedTileSource;
if (!cachedTilesources) cachedTilesources = [NSMutableDictionary new];
if ([cachedTilesources count] > 3) [cachedTilesources removeAllObjects];
NSAssert(([tileSource minZoom] - minZoom) <= 1.0, @"Graphics & memory are overly taxed if [contents minZoom] is more than 1.5 smaller than [tileSource minZoom]");
RMCachedTileSource *newCachedTileSource = [cachedTilesources objectForKey:[newTileSource uniqueTilecacheKey]];
if (!newCachedTileSource) {
newCachedTileSource = [RMCachedTileSource cachedTileSourceWithSource:newTileSource];
minZoom = newCachedTileSource.minZoom;
maxZoom = newCachedTileSource.maxZoom + 1;
if ([newTileSource uniqueTilecacheKey])
[cachedTilesources setObject:newCachedTileSource forKey:[newTileSource uniqueTilecacheKey]];
}
[self setZoom:[self zoom]]; // setZoom clamps zoom level to min/max limits
[tileSource autorelease];
tileSource = [newCachedTileSource retain];
if (([tileSource minZoom] - minZoom) <= 1.0) {
RMLog(@"Graphics & memory are overly taxed if [contents minZoom] is more than 1.5 smaller than [tileSource minZoom]");
}
[projection release];
projection = [[tileSource projection] retain];
[mercatorToTileProjection release];
mercatorToTileProjection = [[tileSource mercatorToTileProjection] retain];
tileSourceProjectedBounds = (RMProjectedRect)[self projectedRectFromLatLonBounds:[tileSource latitudeLongitudeBoundingBox]];
[imagesOnScreen setTileSource:tileSource];
[tileLoader reset];
[tileLoader reset];
[tileLoader reload];
}
... ...
... ... @@ -125,21 +125,24 @@ typedef struct {
id<RMMapViewDelegate> delegate;
BOOL enableDragging;
BOOL enableZoom;
BOOL enableRotate;
BOOL enableRotate;
RMGestureDetails lastGesture;
float decelerationFactor;
BOOL deceleration;
CGFloat rotation;
CGFloat rotation;
@private
BOOL _delegateHasBeforeMapMove;
BOOL _delegateHasAfterMapMove;
BOOL _delegateHasAfterMapMoveDeceleration;
BOOL _delegateHasBeforeMapZoomByFactor;
BOOL _delegateHasAfterMapZoomByFactor;
BOOL _delegateHasBeforeMapRotate;
BOOL _delegateHasAfterMapRotate;
BOOL _delegateHasDoubleTapOnMap;
BOOL _delegateHasDoubleTapTwoFingersOnMap;
BOOL _delegateHasSingleTapOnMap;
BOOL _delegateHasLongSingleTapOnMap;
BOOL _delegateHasTapOnMarker;
BOOL _delegateHasTapOnLabelForMarker;
BOOL _delegateHasAfterMapTouch;
... ... @@ -150,6 +153,8 @@ typedef struct {
NSTimer *_decelerationTimer;
CGSize _decelerationDelta;
CGPoint _longPressPosition;
BOOL _constrainMovement;
RMProjectedPoint NEconstraint, SWconstraint;
... ... @@ -175,8 +180,6 @@ typedef struct {
@property (readonly) CGFloat rotation;
- (id)initWithFrame:(CGRect)frame WithLocation:(CLLocationCoordinate2D)latlong;
/// recenter the map on #latlong, expressed as CLLocationCoordinate2D (latitude/longitude)
- (void)moveToLatLong: (CLLocationCoordinate2D)latlong;
/// recenter the map on #aPoint, expressed in projected meters
... ... @@ -193,5 +196,4 @@ typedef struct {
- (void)setRotation:(CGFloat)angle;
@end
... ...
... ... @@ -44,7 +44,6 @@
@end
@implementation RMMapView
@synthesize contents;
@synthesize decelerationFactor;
@synthesize deceleration;
... ... @@ -62,7 +61,7 @@
- (RMMarkerManager*)markerManager
{
return self.contents.markerManager;
return contents.markerManager;
}
-(void) performInitialSetup
... ... @@ -91,40 +90,28 @@
{
LogMethod();
if (self = [super initWithFrame:frame]) {
contents = nil;
[self performInitialSetup];
}
return self;
}
/// \deprecated Deprecated any time after 0.5.
- (id)initWithFrame:(CGRect)frame WithLocation:(CLLocationCoordinate2D)latlon
{
WarnDeprecated();
LogMethod();
if (self = [super initWithFrame:frame]) {
[self performInitialSetup];
}
[self moveToLatLong:latlon];
return self;
}
//===========================================================
// contents
//===========================================================
- (RMMapContents *)contents
{
if (!_contentsIsSet) {
RMMapContents *newContents = [[RMMapContents alloc] initWithView:self];
self.contents = newContents;
[newContents release];
contents = [[RMMapContents alloc] initWithView:self];
_contentsIsSet = YES;
}
return contents;
}
- (void)setContents:(RMMapContents *)theContents
{
if (contents != theContents) {
[contents release];
[contents autorelease];
contents = [theContents retain];
_contentsIsSet = YES;
[self performInitialSetup];
... ... @@ -134,13 +121,15 @@
-(void) dealloc
{
LogMethod();
self.contents = nil;
[self setDelegate:nil];
[self stopDeceleration];
[contents release]; contents = nil;
[super dealloc];
}
-(void) drawRect: (CGRect) rect
{
[self.contents drawRect:rect];
[contents drawRect:rect];
}
-(NSString*) description
... ... @@ -154,8 +143,8 @@
{
SEL aSelector = [invocation selector];
if ([self.contents respondsToSelector:aSelector])
[invocation invokeWithTarget:self.contents];
if ([contents respondsToSelector:aSelector])
[invocation invokeWithTarget:contents];
else
[self doesNotRecognizeSelector:aSelector];
}
... ... @@ -165,7 +154,7 @@
if ([super respondsToSelector:aSelector])
return [super methodSignatureForSelector:aSelector];
else
return [self.contents methodSignatureForSelector:aSelector];
return [contents methodSignatureForSelector:aSelector];
}
#pragma mark Delegate
... ... @@ -179,7 +168,8 @@
_delegateHasBeforeMapMove = [(NSObject*) delegate respondsToSelector: @selector(beforeMapMove:)];
_delegateHasAfterMapMove = [(NSObject*) delegate respondsToSelector: @selector(afterMapMove:)];
_delegateHasAfterMapMoveDeceleration = [(NSObject*) delegate respondsToSelector: @selector(afterMapMoveDeceleration:)];
_delegateHasBeforeMapZoomByFactor = [(NSObject*) delegate respondsToSelector: @selector(beforeMapZoom: byFactor: near:)];
_delegateHasAfterMapZoomByFactor = [(NSObject*) delegate respondsToSelector: @selector(afterMapZoom: byFactor: near:)];
... ... @@ -187,8 +177,10 @@
_delegateHasAfterMapRotate = [(NSObject*) delegate respondsToSelector: @selector(afterMapRotate: toAngle:)];
_delegateHasDoubleTapOnMap = [(NSObject*) delegate respondsToSelector: @selector(doubleTapOnMap:At:)];
_delegateHasDoubleTapTwoFingersOnMap = [(NSObject *)delegate respondsToSelector:@selector(doubleTapTwoFingersOnMap:At:)];
_delegateHasSingleTapOnMap = [(NSObject*) delegate respondsToSelector: @selector(singleTapOnMap:At:)];
_delegateHasLongSingleTapOnMap = [(NSObject *) delegate respondsToSelector: @selector(longSingleTapOnMap:At:)];
_delegateHasTapOnMarker = [(NSObject*) delegate respondsToSelector:@selector(tapOnMarker:onMap:)];
_delegateHasTapOnLabelForMarker = [(NSObject*) delegate respondsToSelector:@selector(tapOnLabelForMarker:onMap:)];
... ... @@ -210,13 +202,14 @@
-(void) moveToProjectedPoint: (RMProjectedPoint) aPoint
{
if (_delegateHasBeforeMapMove) [delegate beforeMapMove: self];
[self.contents moveToProjectedPoint:aPoint];
[contents moveToProjectedPoint:aPoint];
if (_delegateHasAfterMapMove) [delegate afterMapMove: self];
}
-(void) moveToLatLong: (CLLocationCoordinate2D) point
{
if (_delegateHasBeforeMapMove) [delegate beforeMapMove: self];
[self.contents moveToLatLong:point];
[contents moveToLatLong:point];
if (_delegateHasAfterMapMove) [delegate afterMapMove: self];
}
... ... @@ -267,7 +260,7 @@
}
if (_delegateHasBeforeMapMove) [delegate beforeMapMove: self];
[self.contents moveBy:delta];
[contents moveBy:delta];
if (_delegateHasAfterMapMove) [delegate afterMapMove: self];
}
... ... @@ -350,11 +343,16 @@
}
if (_delegateHasBeforeMapZoomByFactor) [delegate beforeMapZoom: self byFactor: zoomFactor near: center];
[self.contents zoomByFactor:zoomFactor near:center animated:animated withCallback:(animated && _delegateHasAfterMapZoomByFactor)?self:nil];
[contents zoomByFactor:zoomFactor near:center animated:animated withCallback:(animated && _delegateHasAfterMapZoomByFactor)?self:nil];
if (!animated)
if (_delegateHasAfterMapZoomByFactor) [delegate afterMapZoom: self byFactor: zoomFactor near: center];
}
- (void)zoomWithLatLngBoundsNorthEast:(CLLocationCoordinate2D)ne SouthWest:(CLLocationCoordinate2D)sw
{
[contents zoomWithLatLngBoundsNorthEast:ne SouthWest:sw];
[self moveBy:CGSizeZero];
}
#pragma mark RMMapContentsAnimationCallback methods
... ... @@ -450,12 +448,18 @@
[self performSelector:@selector(resumeExpensiveOperations) withObject:nil afterDelay:0.4];
}
- (void)handleLongPress
{
if (_delegateHasLongSingleTapOnMap)
[delegate longSingleTapOnMap:self At:_longPressPosition];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[touches allObjects] objectAtIndex:0];
//Check if the touch hit a RMMarker subclass and if so, forward the touch event on
//so it can be handled there
id furthestLayerDown = [self.contents.overlay hitTest:[touch locationInView:self]];
id furthestLayerDown = [contents.overlay hitTest:[touch locationInView:self]];
if ([[furthestLayerDown class]isSubclassOfClass: [RMMarker class]]) {
if ([furthestLayerDown respondsToSelector:@selector(touchesBegan:withEvent:)]) {
[furthestLayerDown performSelector:@selector(touchesBegan:withEvent:) withObject:touches withObject:event];
... ... @@ -478,6 +482,16 @@
}
}
_longPressPosition = lastGesture.center;
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(handleLongPress) object:nil];
if (lastGesture.numTouches == 1) {
CALayer* hit = [contents.overlay hitTest:[touch locationInView:self]];
if (!hit || ![hit isKindOfClass: [RMMarker class]]) {
[self performSelector:@selector(handleLongPress) withObject:nil afterDelay:0.5];
}
}
[self delayedResumeExpensiveOperations];
}
... ... @@ -486,9 +500,11 @@
{
UITouch *touch = [[touches allObjects] objectAtIndex:0];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(handleLongPress) object:nil];
//Check if the touch hit a RMMarker subclass and if so, forward the touch event on
//so it can be handled there
id furthestLayerDown = [self.contents.overlay hitTest:[touch locationInView:self]];
id furthestLayerDown = [contents.overlay hitTest:[touch locationInView:self]];
if ([[furthestLayerDown class]isSubclassOfClass: [RMMarker class]]) {
if ([furthestLayerDown respondsToSelector:@selector(touchesCancelled:withEvent:)]) {
[furthestLayerDown performSelector:@selector(touchesCancelled:withEvent:) withObject:touches withObject:event];
... ... @@ -506,7 +522,7 @@
//Check if the touch hit a RMMarker subclass and if so, forward the touch event on
//so it can be handled there
id furthestLayerDown = [self.contents.overlay hitTest:[touch locationInView:self]];
id furthestLayerDown = [contents.overlay hitTest:[touch locationInView:self]];
if ([[furthestLayerDown class]isSubclassOfClass: [RMMarker class]]) {
if ([furthestLayerDown respondsToSelector:@selector(touchesEnded:withEvent:)]) {
[furthestLayerDown performSelector:@selector(touchesEnded:withEvent:) withObject:touches withObject:event];
... ... @@ -519,15 +535,28 @@
lastGesture = [self gestureDetails:[event allTouches]];
BOOL decelerating = NO;
if (touch.tapCount >= 2)
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(handleLongPress) object:nil];
if (touch.tapCount >= 2)
{
BOOL twoFingerTap = [touches count] >= 2;
if (_delegateHasDoubleTapOnMap) {
[delegate doubleTapOnMap: self At: lastGesture.center];
if (twoFingerTap) {
if (_delegateHasDoubleTapTwoFingersOnMap) [delegate doubleTapTwoFingersOnMap: self At: lastGesture.center];
} else {
if (_delegateHasDoubleTapOnMap) [delegate doubleTapOnMap: self At: lastGesture.center];
}
} else {
// Default behaviour matches built in maps.app
float nextZoomFactor = [self.contents nextNativeZoomFactor];
if (nextZoomFactor != 0)
[self zoomByFactor:nextZoomFactor near:[touch locationInView:self] animated:YES];
float nextZoomFactor = 0;
if (twoFingerTap) {
nextZoomFactor = [contents prevNativeZoomFactor];
} else {
nextZoomFactor = [contents nextNativeZoomFactor];
}
if (nextZoomFactor != 0)
[self zoomByFactor:nextZoomFactor near:[touch locationInView:self] animated:YES];
}
} else if (lastTouches == 1 && touch.tapCount != 1) {
// deceleration
... ... @@ -541,19 +570,17 @@
}
}
// If there are no more fingers on the screen, resume any slow operations.
if (lastGesture.numTouches == 0 && !decelerating)
{
[self delayedResumeExpensiveOperations];
}
if (touch.tapCount == 1)
{
if(lastGesture.numTouches == 0)
{
CALayer* hit = [self.contents.overlay hitTest:[touch locationInView:self]];
CALayer* hit = [contents.overlay hitTest:[touch locationInView:self]];
// RMLog(@"LAYER of type %@",[hit description]);
if (hit != nil) {
... ... @@ -579,7 +606,7 @@
}
else if(!enableDragging && (lastGesture.numTouches == 1))
{
float prevZoomFactor = [self.contents prevNativeZoomFactor];
float prevZoomFactor = [contents prevNativeZoomFactor];
if (prevZoomFactor != 0)
[self zoomByFactor:prevZoomFactor near:[touch locationInView:self] animated:YES];
}
... ... @@ -594,7 +621,7 @@
//Check if the touch hit a RMMarker subclass and if so, forward the touch event on
//so it can be handled there
id furthestLayerDown = [self.contents.overlay hitTest:[touch locationInView:self]];
id furthestLayerDown = [contents.overlay hitTest:[touch locationInView:self]];
if ([[furthestLayerDown class]isSubclassOfClass: [RMMarker class]]) {
if ([furthestLayerDown respondsToSelector:@selector(touchesMoved:withEvent:)]) {
[furthestLayerDown performSelector:@selector(touchesMoved:withEvent:) withObject:touches withObject:event];
... ... @@ -602,7 +629,14 @@
}
}
CALayer* hit = [self.contents.overlay hitTest:[touch locationInView:self]];
RMGestureDetails newGesture = [self gestureDetails:[event allTouches]];
CGPoint newLongPressPosition = newGesture.center;
CGFloat dx = newLongPressPosition.x - _longPressPosition.x;
CGFloat dy = newLongPressPosition.y - _longPressPosition.y;
if (sqrt(dx*dx + dy*dy) > 5)
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(handleLongPress) object:nil];
CALayer* hit = [contents.overlay hitTest:[touch locationInView:self]];
// RMLog(@"LAYER of type %@",[hit description]);
if (hit != nil) {
... ... @@ -617,9 +651,7 @@
}
}
}
RMGestureDetails newGesture = [self gestureDetails:[event allTouches]];
if(enableRotate && (newGesture.numTouches == lastGesture.numTouches))
{
if(newGesture.numTouches == 2)
... ... @@ -665,10 +697,10 @@
_decelerationDelta = delta;
if ( !_decelerationTimer ) {
_decelerationTimer = [NSTimer scheduledTimerWithTimeInterval:0.01f
target:self
selector:@selector(incrementDeceleration:)
userInfo:nil
repeats:YES];
target:self
selector:@selector(incrementDeceleration:)
userInfo:nil
repeats:YES];
}
}
}
... ... @@ -684,7 +716,7 @@
}
// avoid calling delegate methods? design call here
[self.contents moveBy:_decelerationDelta];
[self moveBy:_decelerationDelta];
_decelerationDelta.width *= [self decelerationFactor];
_decelerationDelta.height *= [self decelerationFactor];
... ... @@ -699,6 +731,9 @@
// call delegate methods; design call (see above)
[self moveBy:CGSizeZero];
}
if (_delegateHasAfterMapMoveDeceleration)
[delegate afterMapMoveDeceleration:self];
}
/// Must be called by higher didReceiveMemoryWarning
... ...
... ... @@ -37,6 +37,7 @@
- (void) beforeMapMove: (RMMapView*) map;
- (void) afterMapMove: (RMMapView*) map ;
- (void) afterMapMoveDeceleration: (RMMapView*) map;
- (void) beforeMapZoom: (RMMapView*) map byFactor: (float) zoomFactor near:(CGPoint) center;
- (void) afterMapZoom: (RMMapView*) map byFactor: (float) zoomFactor near:(CGPoint) center;
... ... @@ -45,7 +46,9 @@
- (void) afterMapRotate: (RMMapView*) map toAngle: (CGFloat) angle;
- (void) doubleTapOnMap: (RMMapView*) map At: (CGPoint) point;
- (void) doubleTapTwoFingersOnMap: (RMMapView*) map At: (CGPoint) point;
- (void) singleTapOnMap: (RMMapView*) map At: (CGPoint) point;
- (void) longSingleTapOnMap: (RMMapView*) map At: (CGPoint) point;
- (void) tapOnMarker: (RMMarker*) marker onMap: (RMMapView*) map;
- (void) tapOnLabelForMarker: (RMMarker*) marker onMap: (RMMapView*) map;
... ...
... ... @@ -90,6 +90,7 @@
}
}
return self;
}
... ...
... ... @@ -31,7 +31,12 @@
/// the interface between RMDatabaseCache and FMDB
@interface RMTileCacheDAO : NSObject {
FMDatabase* db;
FMDatabase* db;
NSUInteger tileCount;
NSOperationQueue *writeQueue;
NSRecursiveLock *writeQueueLock;
}
-(id) initWithDatabase: (NSString*)path;
... ... @@ -41,7 +46,6 @@
-(void) touchTile: (uint64_t) tileHash withDate: (NSDate*) date;
-(void) addData: (NSData*) data LastUsed: (NSDate*)date ForTile: (uint64_t) tileHash;
-(void) purgeTiles: (NSUInteger) count;
-(void) purgeTilesFromBefore: (NSDate*) date;
-(void) removeAllCachedImages;
-(void)didReceiveMemoryWarning;
... ...
... ... @@ -30,16 +30,18 @@
#import "RMTileCache.h"
#import "RMTileImage.h"
@interface RMTileCacheDAO ()
- (NSUInteger)countTiles;
@end
@implementation RMTileCacheDAO
-(void)configureDBForFirstUse
{
[db executeQuery:@"PRAGMA synchronous=OFF"];
[db executeQuery:@"PRAGMA journal_mode=OFF"];
[db executeUpdate:@"CREATE TABLE IF NOT EXISTS ZCACHE (ztileHash INTEGER PRIMARY KEY, zlastUsed DOUBLE, zdata BLOB)"];
[db executeUpdate:@"CREATE INDEX IF NOT EXISTS zlastUsedIndex ON ZCACHE(zLastUsed)"];
// adding more than once does not seem to break anything
[db executeUpdate:@"ALTER TABLE ZCACHE ADD COLUMN zInserted DOUBLE"];
[db executeUpdate:@"CREATE INDEX IF NOT EXISTS zInsertedIndex ON ZCACHE(zInserted)"];
}
-(id) initWithDatabase: (NSString*)path
... ... @@ -47,8 +49,12 @@
if (![super init])
return nil;
writeQueue = [NSOperationQueue new];
[writeQueue setMaxConcurrentOperationCount:1];
writeQueueLock = [NSRecursiveLock new];
RMLog(@"Opening database at %@", path);
db = [[FMDatabase alloc] initWithPath:path];
if (![db open])
{
... ... @@ -57,129 +63,136 @@
}
[db setCrashOnErrors:TRUE];
[db setShouldCacheStatements:TRUE];
[db setShouldCacheStatements:TRUE];
[self configureDBForFirstUse];
tileCount = [self countTiles];
return self;
}
- (void)dealloc
{
LogMethod();
[db release];
[super dealloc];
LogMethod();
[writeQueueLock lock];
[writeQueue release]; writeQueue = nil;
[writeQueueLock unlock];
[writeQueueLock release]; writeQueueLock = nil;
[db close]; [db release]; db = nil;
[super dealloc];
}
- (NSUInteger)count
{
return tileCount;
}
-(NSUInteger) count
- (NSUInteger)countTiles
{
FMResultSet *results = [db executeQuery:@"SELECT COUNT(ztileHash) FROM ZCACHE"];
[writeQueueLock lock];
NSUInteger count = 0;
FMResultSet *results = [db executeQuery:@"SELECT COUNT(ztileHash) FROM ZCACHE"];
if ([results next])
count = [results intForColumnIndex:0];
else
{
RMLog(@"Unable to count columns");
}
RMLog(@"Unable to count columns");
[results close];
[writeQueueLock unlock];
return count;
}
-(NSData*) dataForTile: (uint64_t) tileHash
-(NSData *)dataForTile:(uint64_t)tileHash
{
[writeQueueLock lock];
FMResultSet *results = [db executeQuery:@"SELECT zdata FROM ZCACHE WHERE ztilehash = ?", [NSNumber numberWithUnsignedLongLong:tileHash]];
if ([db hadError])
{
if ([db hadError]) {
RMLog(@"DB error while fetching tile data: %@", [db lastErrorMessage]);
return nil;
}
NSData *data = nil;
NSData *data = nil;
if ([results next])
{
data = [results dataForColumnIndex:0];
}
[results close];
[writeQueueLock unlock];
return data;
}
-(void) purgeTiles: (NSUInteger) count;
{
RMLog(@"purging %u old tiles from db cache", count);
// does not work: "DELETE FROM ZCACHE ORDER BY zlastUsed LIMIT"
BOOL result = [db executeUpdate: @"DELETE FROM ZCACHE WHERE ztileHash IN (SELECT ztileHash FROM ZCACHE ORDER BY zlastUsed LIMIT ? )",
[NSNumber numberWithUnsignedInt: count]];
if (result == NO) {
RMLog(@"Error purging cache");
}
RMLog(@"purging %u old tiles from db cache", count);
}
[writeQueueLock lock];
BOOL result = [db executeUpdate: @"DELETE FROM ZCACHE WHERE ztileHash IN (SELECT ztileHash FROM ZCACHE ORDER BY zlastUsed LIMIT ? )", [NSNumber numberWithUnsignedInt: count]];
[db executeQuery:@"VACUUM"];
tileCount = [self countTiles];
[writeQueueLock unlock];
-(void) purgeTilesFromBefore: (NSDate*) date;
{
NSUInteger count = 0;
FMResultSet *results = [db executeQuery:@"SELECT COUNT(ztileHash) FROM ZCACHE WHERE zInserted < ?", date];
if ([results next]) {
count = [results intForColumnIndex:0];
RMLog(@"Will purge %i tile(s) from before %@", count, date);
}
[results close];
if (count == 0) {
return;
}
BOOL result = [db executeUpdate: @"DELETE FROM ZCACHE WHERE zInserted < ?",
date];
if (result == NO) {
RMLog(@"Error purging cache");
}
if (result == NO) {
RMLog(@"Error purging cache");
}
}
-(void) removeAllCachedImages
{
BOOL result = [db executeUpdate: @"DELETE FROM ZCACHE"];
if (result == NO) {
RMLog(@"Error purging all cache");
}
[writeQueue addOperationWithBlock:^{
[writeQueueLock lock];
BOOL result = [db executeUpdate: @"DELETE FROM ZCACHE"];
[db executeQuery:@"VACUUM"];
[writeQueueLock unlock];
if (result == NO) {
RMLog(@"Error purging all cache");
}
tileCount = [self countTiles];
}];
}
-(void) touchTile: (uint64_t) tileHash withDate: (NSDate*) date
{
BOOL result = [db executeUpdate: @"UPDATE ZCACHE SET zlastUsed = ? WHERE ztileHash = ? ",
date, [NSNumber numberWithUnsignedInt: tileHash]];
if (result == NO) {
RMLog(@"Error touching tile");
}
[writeQueue addOperationWithBlock:^{
[writeQueueLock lock];
BOOL result = [db executeUpdate: @"UPDATE ZCACHE SET zlastUsed = ? WHERE ztileHash = ? ", date, [NSNumber numberWithUnsignedInt: tileHash]];
[writeQueueLock unlock];
if (result == NO) {
RMLog(@"Error touching tile");
}
}];
}
-(void) addData: (NSData*) data LastUsed: (NSDate*)date ForTile: (uint64_t) tileHash
{
// Fixme
// RMLog(@"addData\t%d", tileHash);
BOOL result = [db executeUpdate:@"INSERT OR REPLACE INTO ZCACHE (ztileHash, zlastUsed, zInserted, zdata) VALUES (?, ?, ?, ?)",
[NSNumber numberWithUnsignedLongLong:tileHash], date, [NSDate date], data];
if (result == NO)
{
RMLog(@"Error occured adding data");
}
[writeQueue addOperationWithBlock:^{
// RMLog(@"addData\t%d", tileHash);
[writeQueueLock lock];
BOOL result = [db executeUpdate:@"INSERT OR IGNORE INTO ZCACHE (ztileHash, zlastUsed, zdata) VALUES (?, ?, ?)",
[NSNumber numberWithUnsignedLongLong:tileHash], date, data];
[writeQueueLock unlock];
if (result == NO)
{
RMLog(@"Error occured adding data");
} else
tileCount++;
}];
}
-(void)didReceiveMemoryWarning
{
[db clearCachedStatements];
RMLog(@"Low memory in the tilecache");
[writeQueue cancelAllOperations];
}
@end
... ...
... ... @@ -40,7 +40,6 @@ typedef NSImage UIImage;
#import "FMDatabase.h"
@class RMTileImage;
@class NSData;
@interface RMTileImage : NSObject {
// I know this is a bit nasty.
... ...
... ... @@ -180,15 +180,14 @@
[customActions setObject:[NSNull null] forKey:@"position"];
[customActions setObject:[NSNull null] forKey:@"bounds"];
[customActions setObject:[NSNull null] forKey:kCAOnOrderOut];
[customActions setObject:[NSNull null] forKey:kCAOnOrderIn];
CATransition *fadein = [[CATransition alloc] init];
fadein.duration = 0.3;
fadein.type = kCATransitionReveal;
[customActions setObject:fadein forKey:@"contents"];
[fadein release];
[customActions setObject:[NSNull null] forKey:kCAOnOrderOut];
[customActions setObject:[NSNull null] forKey:kCAOnOrderIn];
CATransition *reveal = [[CATransition alloc] init];
reveal.duration = 0.3;
reveal.type = kCATransitionFade;
[customActions setObject:reveal forKey:@"contents"];
[reveal release];
layer.actions=customActions;
... ...
... ... @@ -147,11 +147,11 @@
{
// RMLog(@"addTile: %d %d", tile.x, tile.y);
RMTileImage *dummyTile = [RMTileImage dummyTile:tile];
RMTileImage *tileImage = [images member:dummyTile];
RMTileImage *dummyTile = [RMTileImage dummyTile:tile];
RMTileImage *tileImage = [images member:dummyTile];
if (tileImage != nil)
{
{
[tileImage setScreenLocation:screenLocation];
[images addObject:dummyTile];
}
... ... @@ -214,7 +214,10 @@
[self addTile:normalisedTile At:screenLocation];
}
}
// Performance issue!
break;
// adjust rect for next zoom level down until we're at minimum
if (--rect.origin.tile.zoom <= minimumZoom)
break;
... ...
... ... @@ -65,7 +65,6 @@
-(void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
... ... @@ -105,19 +104,7 @@
if ([content mercatorToTileProjection] == nil || [content
mercatorToScreenProjection] == nil)
return;
// delay display of new images until expensive operations are
//allowed
[[NSNotificationCenter defaultCenter] removeObserver:self
name:RMResumeExpensiveOperations object:nil];
if ([RMMapContents performExpensiveOperations] == NO)
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateLoadedImages)
name:RMResumeExpensiveOperations object:nil];
return;
}
if ([self screenIsLoaded])
return;
... ...