Authored by Michael Tyson

Added Frank Schroeder's DB source patch, plus the scroll limits code

... ... @@ -2,7 +2,7 @@ The Route-Me project is receiving frequent updates from its developer community.
this reason, you'll probably want to have your hands on the source of Route-Me while
you're developing your own project. If you want to link the Route-Me .xcodeproj to your
own program, please follow the Embedding Guide, found at
http://code.google.com/p/route-me/wiki/EmbedingGuide
http://github.com/route-me/route-me/wiki/Embedding-Guide
Use the "MapView" target.
If you just want to produce a static library framework to drop into your app, without project
... ...
//
// RMDBMapSource.h
//
// Copyright (c) 2009, Frank Schroeder, SharpMind GbR
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#import "RMTileSource.h"
#import "RMProjection.h"
#import "FMDatabase.h"
@interface RMDBMapSource : NSObject<RMTileSource> {
// tile database
FMDatabase* db;
// projection
RMFractalTileProjection *tileProjection;
// supported zoom levels
float minZoom;
float maxZoom;
int tileSideLength;
// coverage area
CLLocationCoordinate2D topLeft;
CLLocationCoordinate2D bottomRight;
CLLocationCoordinate2D center;
}
-(id)initWithPath:(NSString*)path;
-(int)tileSideLength;
-(float) minZoom;
-(float) maxZoom;
-(NSString *)shortName;
-(NSString *)longDescription;
-(NSString *)shortAttribution;
-(NSString *)longAttribution;
- (CLLocationCoordinate2D) topLeftOfCoverage;
- (CLLocationCoordinate2D) bottomRightOfCoverage;
- (CLLocationCoordinate2D) centerOfCoverage;
@end
... ...
//
// RMDBMapSource.m
//
// Copyright (c) 2009, Frank Schroeder, SharpMind GbR
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// RMDBMap source is an implementation of an sqlite tile source which is
// can be used as an offline map store.
//
// The implementation expects two tables in the database:
//
// table "preferences" - contains the map meta data as name/value pairs
//
// SQL: create table preferences(name text primary key, value text)
//
// The preferences table must at least contain the following
// values for the tile source to function properly.
//
// * map.minZoom - minimum supported zoom level
// * map.maxZoom - maximum supported zoom level
// * map.tileSideLength - tile size in pixels
//
// Optionally it can contain the following values
//
// Coverage area:
// * map.coverage.topLeft.latitude
// * map.coverage.topLeft.longitude
// * map.coverage.bottomRight.latitude
// * map.coverage.bottomRight.longitude
// * map.coverage.center.latitude
// * map.coverage.center.longitude
//
// Attribution:
// * map.shortName
// * map.shortAttribution
// * map.longDescription
// * map.longAttribution
//
// table "tiles" - contains the tile images
//
// SQL: create table tiles(tilekey integer primary key, image blob)
//
// The tile images are stored in the "image" column as a blob.
// The primary key of the table is the "tilekey" which is computed
// with the RMTileKey function (found in RMTile.h)
//
// uint64_t RMTileKey(RMTile tile);
//
#import "RMDBMapSource.h"
#import "RMTileImage.h"
#import "RMFractalTileProjection.h"
#define kDefaultLatLonBoundingBox ((RMSphericalTrapezium){.northeast = {.latitude = 90, .longitude = 180}, .southwest = {.latitude = -90, .longitude = -180}})
// mandatory preference keys
#define kMinZoomKey @"map.minZoom"
#define kMaxZoomKey @"map.maxZoom"
#define kTileSideLengthKey @"map.tileSideLength"
// optional preference keys for the coverage area
#define kCoverageTopLeftLatitudeKey @"map.coverage.topLeft.latitude"
#define kCoverageTopLeftLongitudeKey @"map.coverage.topLeft.longitude"
#define kCoverageBottomRightLatitudeKey @"map.coverage.bottomRight.latitude"
#define kCoverageBottomRightLongitudeKey @"map.coverage.bottomRight.longitude"
#define kCoverageCenterLatitudeKey @"map.coverage.center.latitude"
#define kCoverageCenterLongitudeKey @"map.coverage.center.longitude"
// optional preference keys for the attribution
#define kShortNameKey @"map.shortName"
#define kLongDescriptionKey @"map.longDescription"
#define kShortAttributionKey @"map.shortAttribution"
#define kLongAttributionKey @"map.longAttribution"
@interface RMDBMapSource(PrivateMethods)
- (NSString*)getPreferenceAsString:(NSString*)name;
- (float)getPreferenceAsFloat:(NSString*)name;
- (int)getPreferenceAsInt:(NSString*)name;
@end
@implementation RMDBMapSource
-(id)initWithPath:(NSString*)path {
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]) {
RMLog(@"Opening db map source %@", path);
// get the tile side length
tileSideLength = [self getPreferenceAsInt:kTileSideLengthKey];
// get the supported zoom levels
minZoom = [self getPreferenceAsFloat:kMinZoomKey];
maxZoom = [self getPreferenceAsFloat:kMaxZoomKey];
// get the coverage area
topLeft.latitude = [self getPreferenceAsFloat:kCoverageTopLeftLatitudeKey];
topLeft.longitude = [self getPreferenceAsFloat:kCoverageTopLeftLongitudeKey];
bottomRight.latitude = [self getPreferenceAsFloat:kCoverageBottomRightLatitudeKey];
bottomRight.longitude = [self getPreferenceAsFloat:kCoverageBottomRightLatitudeKey];
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(@"Coverage area: (%2.6f,%2.6f) x (%2.6f,%2.6f)",
topLeft.latitude,
topLeft.longitude,
bottomRight.latitude,
bottomRight.longitude);
RMLog(@"Center: (%2.6f,%2.6f)",
center.latitude,
center.longitude);
} else {
RMLog(@"Error opening db map source %@", path);
}
// init the tile projection
tileProjection = [[RMFractalTileProjection alloc] initFromProjection:[self projection] tileSideLength:tileSideLength maxZoom:maxZoom minZoom:minZoom];
}
return self;
}
-(void) dealloc {
[db release];
[tileProjection release];
[super dealloc];
}
-(int)tileSideLength {
return tileSideLength;
}
- (CLLocationCoordinate2D) topLeftOfCoverage {
return topLeft;
}
- (CLLocationCoordinate2D) bottomRightOfCoverage {
return bottomRight;
}
- (CLLocationCoordinate2D) centerOfCoverage {
return center;
}
#pragma mark RMTileSource methods
-(float) minZoom {
return minZoom;
}
-(float) maxZoom {
return maxZoom;
}
-(void) setMinZoom:(NSUInteger)aMinZoom
{
[tileProjection setMinZoom:aMinZoom];
}
-(void) setMaxZoom:(NSUInteger)aMaxZoom
{
[tileProjection setMaxZoom:aMaxZoom];
}
-(RMSphericalTrapezium) latitudeLongitudeBoundingBox;
{
return kDefaultLatLonBoundingBox;
}
-(NSString*) tileURL: (RMTile) tile {
return nil;
}
-(NSString*) tileFile: (RMTile) tile {
return nil;
}
-(NSString*) tilePath {
return nil;
}
-(RMTileImage *)tileImage:(RMTile)tile {
tile = [tileProjection normaliseTile:tile];
return [RMTileImage imageForTile:tile fromDB:db];
}
-(id<RMMercatorToTileProjection>) mercatorToTileProjection {
return [[tileProjection retain] autorelease];
}
-(RMProjection*) projection {
return [RMProjection googleProjection];
}
-(void) didReceiveMemoryWarning {
LogMethod();
}
-(NSString*) uniqueTilecacheKey {
return nil;
}
-(NSString *)shortName {
return [self getPreferenceAsString:kShortNameKey];
}
-(NSString *)longDescription {
return [self getPreferenceAsString:kLongDescriptionKey];
}
-(NSString *)shortAttribution {
return [self getPreferenceAsString:kShortAttributionKey];
}
-(NSString *)longAttribution {
return [self getPreferenceAsString:kLongAttributionKey];
}
-(void)removeAllCachedImages {
// no-op
}
#pragma mark preference methods
-(NSString*)getPreferenceAsString:(NSString*)name {
NSString* value = nil;
FMResultSet* rs = [db executeQuery:@"select value from preferences where name = ?", name];
if ([rs next]) {
value = [rs stringForColumn:@"value"];
}
[rs close];
return value;
}
-(float)getPreferenceAsFloat:(NSString*)name {
NSString* value = [self getPreferenceAsString:name];
return (value == nil) ? INT_MIN : [value floatValue];
}
-(int)getPreferenceAsInt:(NSString*)name {
NSString* value = [self getPreferenceAsString:name];
return (value == nil) ? INT_MIN : [value intValue];
}
@end
... ...
//
// RMDBTileImage.h
//
// Copyright (c) 2009, Frank Schroeder, SharpMind GbR
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#import "RMTileImage.h"
@interface RMDBTileImage : RMTileImage {}
- (id)initWithTile:(RMTile)tile fromDB:(FMDatabase*)db;
@end
... ...
//
// RMDBTileImage.m
//
// Copyright (c) 2009, Frank Schroeder, SharpMind GbR
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// RMDBTileImage is a tile image implementation for the RMDBMapSource.
//
// See RMDBMapSource.m for a full documentation on the database schema.
//
#import "RMDBTileImage.h"
#define FMDBErrorCheck(db) { if ([db hadError]) { NSLog(@"DB error %d on line %d: %@", [db lastErrorCode], __LINE__, [db lastErrorMessage]); } }
@implementation RMDBTileImage
- (id)initWithTile:(RMTile)_tile fromDB:(FMDatabase*)db {
self = [super initWithTile:_tile];
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);
// 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]];
}
[rs close];
}
return self;
}
@end
... ...
... ... @@ -150,6 +150,9 @@ typedef struct {
NSTimer *_decelerationTimer;
CGSize _decelerationDelta;
BOOL _constrainMovement;
RMProjectedPoint NEconstraint, SWconstraint;
BOOL _contentsIsSet; // "contents" must be set, but is initialized lazily to allow apps to override defaults in -awakeFromNib
}
... ... @@ -180,6 +183,9 @@ typedef struct {
- (void)moveToProjectedPoint: (RMProjectedPoint)aPoint;
- (void)moveBy: (CGSize) delta;
-(void)setConstraintsSW:(CLLocationCoordinate2D)sw NE:(CLLocationCoordinate2D)ne;
- (void)zoomByFactor: (float) zoomFactor near:(CGPoint) aPoint;
- (void)zoomByFactor: (float) zoomFactor near:(CGPoint) aPoint animated:(BOOL)animated;
... ... @@ -187,4 +193,5 @@ typedef struct {
- (void)setRotation:(CGFloat)angle;
@end
... ...
... ... @@ -33,7 +33,7 @@
#import "RMMercatorToScreenProjection.h"
#import "RMMarker.h"
#import "RMProjection.h"
#import "RMMarkerManager.h"
@interface RMMapView (PrivateMethods)
... ... @@ -82,6 +82,8 @@
self.backgroundColor = [UIColor grayColor];
_constrainMovement=NO;
// [[NSURLCache sharedURLCache] removeAllCachedResponses];
}
... ... @@ -218,18 +220,118 @@
if (_delegateHasAfterMapMove) [delegate afterMapMove: self];
}
- (void)moveBy: (CGSize) delta
{
-(void)setConstraintsSW:(CLLocationCoordinate2D)sw NE:(CLLocationCoordinate2D)ne{
//store projections
RMProjection *proj=self.contents.projection;
NEconstraint = [proj latLongToPoint:ne];
SWconstraint = [proj latLongToPoint:sw];
_constrainMovement=YES;
}
-(void)moveBy:(CGSize)delta {
if ( _constrainMovement )
{
//bounds are
RMMercatorToScreenProjection *mtsp=self.contents.mercatorToScreenProjection;
//calculate new bounds after move
RMProjectedRect pBounds=[mtsp projectedBounds];
RMProjectedSize XYDelta = [mtsp projectScreenSizeToXY:delta];
RMProjectedRect newBounds=pBounds;
//move the rect by delta
newBounds.origin.northing -= XYDelta.height;
newBounds.origin.easting -= XYDelta.width;
//let's see if new bounds are within constrained bounds
if(newBounds.origin.northing < SWconstraint.northing || newBounds.origin.northing+newBounds.size.height > NEconstraint.northing ||
newBounds.origin.easting < SWconstraint.easting || newBounds.origin.easting+newBounds.size.width > NEconstraint.easting){
RMLog(@"Out of bounds: don't move");
return;
}
}
if (_delegateHasBeforeMapMove) [delegate beforeMapMove: self];
[self.contents moveBy:delta];
if (_delegateHasAfterMapMove) [delegate afterMapMove: self];
}
- (void)zoomByFactor: (float) zoomFactor near:(CGPoint) center
{
[self zoomByFactor:zoomFactor near:center animated:NO];
}
- (void)zoomByFactor: (float) zoomFactor near:(CGPoint) center animated:(BOOL)animated
{
if ( _constrainMovement )
{
//check that bounds after zoom don't exceed map constraints
//the logic is copued from the method zoomByFactor,
float _zoomFactor = [self.contents adjustZoomForBoundingMask:zoomFactor];
float zoomDelta = log2f(_zoomFactor);
float targetZoom = zoomDelta + [self.contents zoom];
BOOL canZoom=NO;
if (targetZoom == [self.contents zoom]){
//OK... . I could even do a return here.. but it will hamper with future logic..
canZoom=YES;
}
// clamp zoom to remain below or equal to maxZoom after zoomAfter will be applied
if(targetZoom > [self.contents maxZoom]){
_zoomFactor = exp2f([self.contents maxZoom] - [self.contents zoom]);
}
//bools for syntactical sugar to understand the logic in the if statement below
BOOL zoomAtMax = ([self.contents zoom] == [self.contents maxZoom]);
BOOL zoomAtMin = ([self.contents zoom] == [self.contents minZoom]);
BOOL zoomGreaterMin = ([self.contents zoom] > [self.contents minZoom]);
BOOL zoomLessMax = ([self.contents zoom] < [ self.contents maxZoom]);
//zooming in zoomFactor > 1
//zooming out zoomFactor < 1
if ((zoomGreaterMin && zoomLessMax) || (zoomAtMax && zoomFactor<1) || (zoomAtMin && zoomFactor>1))
{
//if I'm here it means I could zoom, now we have to see what will happen after zoom
RMMercatorToScreenProjection *mtsp= self.contents.mercatorToScreenProjection ;
//get copies of mercatorRoScreenProjection's data
RMProjectedPoint origin=[mtsp origin];
float metersPerPixel=mtsp.metersPerPixel;
CGRect screenBounds=[mtsp screenBounds];
//tjis is copied from [RMMercatorToScreenBounds zoomScreenByFactor]
// First we move the origin to the pivot...
origin.easting += center.x * metersPerPixel;
origin.northing += (screenBounds.size.height - center.y) * metersPerPixel;
// Then scale by 1/factor
metersPerPixel /= _zoomFactor;
// Then translate back
origin.easting -= center.x * metersPerPixel;
origin.northing -= (screenBounds.size.height - center.y) * metersPerPixel;
origin = [mtsp.projection wrapPointHorizontally:origin];
//calculate new bounds
RMProjectedRect zRect;
zRect.origin = origin;
zRect.size.width = screenBounds.size.width * metersPerPixel;
zRect.size.height = screenBounds.size.height * metersPerPixel;
//can zoom only if within bounds
canZoom= !(zRect.origin.northing < SWconstraint.northing || zRect.origin.northing+zRect.size.height> NEconstraint.northing ||
zRect.origin.easting < SWconstraint.easting || zRect.origin.easting+zRect.size.width > NEconstraint.easting);
}
if(!canZoom){
RMLog(@"Zooming will move map out of bounds: no zoom");
return;
}
}
if (_delegateHasBeforeMapZoomByFactor) [delegate beforeMapZoom: self byFactor: zoomFactor near: center];
[self.contents zoomByFactor:zoomFactor near:center animated:animated withCallback:(animated && _delegateHasAfterMapZoomByFactor)?self:nil];
if (!animated)
... ...
... ... @@ -87,5 +87,8 @@
@property (assign, readwrite) float metersPerPixel;
@property (assign, readwrite) RMProjectedPoint origin;
@property (nonatomic,readonly) RMProjection *projection;
-(void)deepCopy:(RMMercatorToScreenProjection *)copy;
@end
... ...
... ... @@ -30,6 +30,16 @@
@implementation RMMercatorToScreenProjection
@synthesize projection;
@synthesize origin;
-(void)deepCopy:(RMMercatorToScreenProjection *)copy{
screenBounds=copy.screenBounds;
projection=copy.projection;
metersPerPixel=copy.metersPerPixel;
origin=copy.origin;
}
- (id) initFromProjection: (RMProjection*) aProjection ToScreenBounds: (CGRect)aScreenBounds;
{
if (![super init])
... ...
... ... @@ -37,8 +37,10 @@ typedef NSImage UIImage;
#import "RMNotifications.h"
#import "RMTile.h"
#import "RMTileProxy.h"
#import "FMDatabase.h"
@class RMTileImage;
@class NSData;
@interface RMTileImage : NSObject {
// I know this is a bit nasty.
... ... @@ -64,6 +66,7 @@ typedef NSImage UIImage;
+ (RMTileImage*)imageForTile: (RMTile) tile withURL: (NSString*)url;
+ (RMTileImage*)imageForTile: (RMTile) tile fromFile: (NSString*)filename;
+ (RMTileImage*)imageForTile: (RMTile) tile withData: (NSData*)data;
+ (RMTileImage*)imageForTile: (RMTile) tile fromDB: (FMDatabase*)db;
- (void)moveBy: (CGSize) delta;
- (void)zoomByFactor: (float) zoomFactor near:(CGPoint) center;
... ...
... ... @@ -29,6 +29,7 @@
#import "RMWebTileImage.h"
#import "RMTileLoader.h"
#import "RMFileTileImage.h"
#import "RMDBTileImage.h"
#import "RMTileCache.h"
#import "RMPixel.h"
#import <QuartzCore/QuartzCore.h>
... ... @@ -115,6 +116,11 @@
return [tileImage autorelease];
}
+ (RMTileImage*)imageForTile:(RMTile) _tile fromDB: (FMDatabase*)db
{
return [[[RMDBTileImage alloc] initWithTile: _tile fromDB:db] autorelease];
}
-(void) cancelLoading
{
[[NSNotificationCenter defaultCenter] postNotificationName:RMMapImageLoadingCancelledNotification
... ...
... ... @@ -182,6 +182,10 @@
B8F3FC650EA2E792004D8F85 /* RMMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = B8F3FC630EA2E792004D8F85 /* RMMarker.m */; };
B8FA92190E9315EC003A9FE6 /* RMLayerCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = B8FA92170E9315EC003A9FE6 /* RMLayerCollection.h */; };
B8FA921A0E9315EC003A9FE6 /* RMLayerCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = B8FA92180E9315EC003A9FE6 /* RMLayerCollection.m */; };
D1437B34122869E400888DAE /* RMDBTileImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D1437B30122869E400888DAE /* RMDBTileImage.m */; };
D1437B35122869E400888DAE /* RMDBTileImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D1437B31122869E400888DAE /* RMDBTileImage.h */; };
D1437B36122869E400888DAE /* RMDBMapSource.m in Sources */ = {isa = PBXBuildFile; fileRef = D1437B32122869E400888DAE /* RMDBMapSource.m */; };
D1437B37122869E400888DAE /* RMDBMapSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D1437B33122869E400888DAE /* RMDBMapSource.h */; };
F5C12D2A0F8A86CA00A894D2 /* RMGeoHash.h in Headers */ = {isa = PBXBuildFile; fileRef = F5C12D280F8A86CA00A894D2 /* RMGeoHash.h */; };
F5C12D2B0F8A86CA00A894D2 /* RMGeoHash.m in Sources */ = {isa = PBXBuildFile; fileRef = F5C12D290F8A86CA00A894D2 /* RMGeoHash.m */; };
/* End PBXBuildFile section */
... ... @@ -348,6 +352,10 @@
C7A967510E8412930031BA75 /* RMAbstractMercatorWebSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMAbstractMercatorWebSource.m; sourceTree = "<group>"; };
C7A9675C0E84134B0031BA75 /* RMVirtualEarthSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMVirtualEarthSource.h; sourceTree = "<group>"; };
C7A9675D0E84134B0031BA75 /* RMVirtualEarthSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMVirtualEarthSource.m; sourceTree = "<group>"; };
D1437B30122869E400888DAE /* RMDBTileImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMDBTileImage.m; sourceTree = "<group>"; };
D1437B31122869E400888DAE /* RMDBTileImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMDBTileImage.h; sourceTree = "<group>"; };
D1437B32122869E400888DAE /* RMDBMapSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMDBMapSource.m; sourceTree = "<group>"; };
D1437B33122869E400888DAE /* RMDBMapSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMDBMapSource.h; sourceTree = "<group>"; };
F5C12D280F8A86CA00A894D2 /* RMGeoHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMGeoHash.h; sourceTree = "<group>"; };
F5C12D290F8A86CA00A894D2 /* RMGeoHash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMGeoHash.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
... ... @@ -531,6 +539,8 @@
children = (
B83E64D80E80E73F001663B6 /* RMTileImage.h */,
B83E64D90E80E73F001663B6 /* RMTileImage.m */,
D1437B30122869E400888DAE /* RMDBTileImage.m */,
D1437B31122869E400888DAE /* RMDBTileImage.h */,
B83E64DA0E80E73F001663B6 /* RMTileProxy.h */,
B83E64DB0E80E73F001663B6 /* RMTileProxy.m */,
B83E64DC0E80E73F001663B6 /* RMWebTileImage.h */,
... ... @@ -589,6 +599,8 @@
B83E64EE0E80E73F001663B6 /* RMOpenStreetMapSource.m */,
C7A9675C0E84134B0031BA75 /* RMVirtualEarthSource.h */,
C7A9675D0E84134B0031BA75 /* RMVirtualEarthSource.m */,
D1437B32122869E400888DAE /* RMDBMapSource.m */,
D1437B33122869E400888DAE /* RMDBMapSource.h */,
B885ABB00EBB1332002206AB /* RMCloudMadeMapSource.h */,
B885ABB10EBB1332002206AB /* RMCloudMadeMapSource.m */,
2B5682700F68E36000E8DF40 /* RMOpenAerialMapSource.h */,
... ... @@ -769,6 +781,8 @@
B144DEFE0FD989C3003F3368 /* RMTileMapServiceSource.h in Headers */,
B1EB26C310B5D8C0009F8658 /* RMOpenCycleMapSource.h in Headers */,
B1EB26C610B5D8E6009F8658 /* RMNotifications.h in Headers */,
D1437B35122869E400888DAE /* RMDBTileImage.h in Headers */,
D1437B37122869E400888DAE /* RMDBMapSource.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
... ... @@ -1009,6 +1023,8 @@
F5C12D2B0F8A86CA00A894D2 /* RMGeoHash.m in Sources */,
B144DEFF0FD989C3003F3368 /* RMTileMapServiceSource.m in Sources */,
B1EB26C410B5D8C0009F8658 /* RMOpenCycleMapSource.m in Sources */,
D1437B34122869E400888DAE /* RMDBTileImage.m in Sources */,
D1437B36122869E400888DAE /* RMDBMapSource.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
... ...
... ... @@ -32,6 +32,11 @@
// have to initialize the RMMapContents object explicitly if we want it to use a particular tilesource
[[[RMMapContents alloc] initWithView:mapView
tilesource:myTilesource] autorelease];
/* -- Uncomment to constrain view
[mapView setConstraintsSW:((CLLocationCoordinate2D){-33.942221,150.996094})
NE:((CLLocationCoordinate2D){-33.771157,151.32019})]; */
[self updateInfo];
}
... ...