Authored by Thomas Rasch

Merge branch 'develop' into release

//
// RMTileStreamSource.h
// RMMapBoxSource.h
//
// Created by Justin R. Miller on 5/17/11.
// Copyright 2011, Development Seed, Inc.
// Copyright 2012 MapBox.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
... ... @@ -15,9 +15,9 @@
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of Development Seed, Inc., nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
// * Neither the name of MapBox, nor the names of its contributors may be
// used to endorse or promote products derived from this software
// without specific prior written permission.
//
// 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
... ... @@ -30,50 +30,43 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// http://mapbox.com/hosting/api/
// This source supports both tiles from MapBox Hosting as well as the open source,
// self-hosted TileStream software.
//
// See samples/MBTilesDemo for example usage
// When initializing an instance, pass in valid TileJSON 2.0.0[1] as returned by
// the MapBox Hosting API[2] or TileStream software[3].
//
// This class supports both the paid, hosted version of TileStream, as well as the
// open source, self-hosted version.
// Example app at https://github.com/mapbox/mapbox-ios-example
//
// When initializing an instance, pass in an info dictionary comprised of the
// following keys. Unless otherwise specified, keys & values are exactly as
// returned by the TileStream REST API.
//
// Example: http://tiles.mapbox.com/mapbox/api/v1/Tileset/geography-class
//
// Required info dictionary keys:
//
// `name`
// `id`
// `version`
// `description`
// `attribution`
// `type`
// `minzoom`
// `maxzoom`
// `bounds`
// `tileURL` (choose a single value from `tiles` as returned by the API)
// [1] https://github.com/mapbox/TileJSON/tree/master/2.0.0
// [2] http://mapbox.com/hosting/api/
// [3] https://github.com/mapbox/tilestream
//
// This class also supports initialization via the deprecated info dictionary
// for backwards compatibility and for iOS < 5.0 where JSON serialization isn't
// built into the SDK. Its use is discouraged.
#import "RMAbstractWebMapSource.h"
#define kTileStreamDefaultTileSize 256
#define kTileStreamDefaultMinTileZoom 0
#define kTileStreamDefaultMaxTileZoom 18
#define kTileStreamDefaultLatLonBoundingBox ((RMSphericalTrapezium){ .northEast = { .latitude = 90, .longitude = 180 }, \
#define kMapBoxDefaultTileSize 256
#define kMapBoxDefaultMinTileZoom 0
#define kMapBoxDefaultMaxTileZoom 18
#define kMapBoxDefaultLatLonBoundingBox ((RMSphericalTrapezium){ .northEast = { .latitude = 90, .longitude = 180 }, \
.southWest = { .latitude = -90, .longitude = -180 } })
@interface RMTileStreamSource : RMAbstractWebMapSource
{
NSDictionary *infoDictionary;
}
@interface RMMapBoxSource : RMAbstractWebMapSource
- (id)initWithReferenceURL:(NSURL *)referenceURL; // Designated initializer. Point to either a remote TileJSON spec or a local TileJSON or property list.
//
// You may also use just `init` to get MapBox Streets by default.
//
- (id)initWithTileJSON:(NSString *)tileJSON; // Initialize source with TileJSON.
- (id)initWithInfo:(NSDictionary *)info; // Initialize source with properly list (deprecated).
- (id)initWithInfo:(NSDictionary *)info;
- (id)initWithReferenceURL:(NSURL *)referenceURL;
- (BOOL)coversFullWorld;
- (NSString *)legend;
- (NSString *)legend; // HTML-formatted legend for this source, if any
- (BOOL)coversFullWorld; // Regional or global coverage?
@property (nonatomic, readonly, retain) NSDictionary *infoDictionary;
... ...
//
// RMTileStreamSource.h
// RMMapBoxSource.m
//
// Created by Justin R. Miller on 5/17/11.
// Copyright 2011, Development Seed, Inc.
// Copyright 2012 MapBox.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
... ... @@ -15,9 +15,9 @@
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of Development Seed, Inc., nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
// * Neither the name of MapBox, nor the names of its contributors may be
// used to endorse or promote products derived from this software
// without specific prior written permission.
//
// 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
... ... @@ -31,9 +31,9 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#import "RMTileStreamSource.h"
#import "RMMapBoxSource.h"
@interface RMTileStreamSource ()
@interface RMMapBoxSource ()
@property (nonatomic, retain) NSDictionary *infoDictionary;
... ... @@ -41,13 +41,34 @@
#pragma mark -
@implementation RMTileStreamSource
@implementation RMMapBoxSource
@synthesize infoDictionary;
- (id)init
{
return [self initWithReferenceURL:[NSURL URLWithString:@"http://api.tiles.mapbox.com/v2/mapbox.mapbox-streets.json"]];
}
- (id)initWithTileJSON:(NSString *)tileJSON
{
if (self = [super init])
{
NSAssert([NSJSONSerialization class], @"JSON serialization not supported by SDK");
infoDictionary = (NSDictionary *)[[NSJSONSerialization JSONObjectWithData:[tileJSON dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:nil] retain];
}
return self;
}
- (id)initWithInfo:(NSDictionary *)info
{
if (!(self = [super init]))
WarnDeprecated();
if ( ! (self = [super init]))
return nil;
infoDictionary = [[NSDictionary dictionaryWithDictionary:info] retain];
... ... @@ -57,7 +78,15 @@
- (id)initWithReferenceURL:(NSURL *)referenceURL
{
return [self initWithInfo:[NSDictionary dictionaryWithContentsOfURL:referenceURL]];
id dataObject;
if ((dataObject = [NSString stringWithContentsOfURL:referenceURL encoding:NSUTF8StringEncoding error:nil]) && dataObject)
return [self initWithTileJSON:dataObject];
else if ((dataObject = [[[NSDictionary alloc] initWithContentsOfURL:referenceURL] autorelease]) && dataObject)
return [self initWithInfo:dataObject];
return nil;
}
- (void)dealloc
... ... @@ -74,9 +103,18 @@
//
NSInteger zoom = tile.zoom;
NSInteger x = tile.x;
NSInteger y = pow(2, zoom) - tile.y - 1;
NSInteger y = tile.y;
if ([self.infoDictionary objectForKey:@"scheme"] && [[self.infoDictionary objectForKey:@"scheme"] isEqual:@"tms"])
y = pow(2, zoom) - tile.y - 1;
NSString *tileURLString = [self.infoDictionary objectForKey:@"tileURL"];
NSString *tileURLString;
if ([self.infoDictionary objectForKey:@"tiles"])
tileURLString = [[self.infoDictionary objectForKey:@"tiles"] objectAtIndex:0];
else
tileURLString = [self.infoDictionary objectForKey:@"tileURL"];
tileURLString = [tileURLString stringByReplacingOccurrencesOfString:@"{z}" withString:[[NSNumber numberWithInteger:zoom] stringValue]];
tileURLString = [tileURLString stringByReplacingOccurrencesOfString:@"{x}" withString:[[NSNumber numberWithInteger:x] stringValue]];
... ... @@ -97,7 +135,15 @@
- (RMSphericalTrapezium)latitudeLongitudeBoundingBox
{
NSArray *parts = [[self.infoDictionary objectForKey:@"bounds"] componentsSeparatedByString:@","];
id bounds = [self.infoDictionary objectForKey:@"bounds"];
NSArray *parts;
if ([bounds isKindOfClass:[NSArray class]])
parts = bounds;
else
parts = [bounds componentsSeparatedByString:@","];
if ([parts count] == 4)
{
... ... @@ -115,13 +161,13 @@
return bounds;
}
return kTileStreamDefaultLatLonBoundingBox;
return kMapBoxDefaultLatLonBoundingBox;
}
- (BOOL)coversFullWorld
{
RMSphericalTrapezium ownBounds = [self latitudeLongitudeBoundingBox];
RMSphericalTrapezium defaultBounds = kTileStreamDefaultLatLonBoundingBox;
RMSphericalTrapezium defaultBounds = kMapBoxDefaultLatLonBoundingBox;
if (ownBounds.southWest.longitude <= defaultBounds.southWest.longitude + 10 &&
ownBounds.northEast.longitude >= defaultBounds.northEast.longitude - 10)
... ... @@ -137,7 +183,7 @@
- (NSString *)uniqueTilecacheKey
{
return [NSString stringWithFormat:@"%@-%@", [self.infoDictionary objectForKey:@"id"], [self.infoDictionary objectForKey:@"version"]];
return [NSString stringWithFormat:@"MapBox-%@-%@", [self.infoDictionary objectForKey:@"id"], [self.infoDictionary objectForKey:@"version"]];
}
- (NSString *)shortName
... ...
... ... @@ -79,10 +79,9 @@
[super dealloc];
}
- (void)setNeedsDisplay
- (void)didMoveToWindow
{
self.contentScaleFactor = 1.0f;
[super setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
... ...
... ... @@ -68,6 +68,8 @@
- (void)correctPositionOfAllAnnotations;
- (void)correctPositionOfAllAnnotationsIncludingInvisibles:(BOOL)correctAllLayers wasZoom:(BOOL)wasZoom;
- (void)correctMinZoomScaleForBoundingMask;
@end
#pragma mark -
... ... @@ -255,6 +257,7 @@
mapScrollView.frame = bounds;
overlayView.frame = bounds;
[self correctPositionOfAllAnnotations];
[self correctMinZoomScaleForBoundingMask];
}
}
... ... @@ -535,6 +538,28 @@
#pragma mark -
#pragma mark Zoom
- (void)setBoundingMask:(NSUInteger)mask
{
boundingMask = mask;
[self correctMinZoomScaleForBoundingMask];
}
- (void)correctMinZoomScaleForBoundingMask
{
if (self.boundingMask != RMMapNoMinBound)
{
CGFloat newMinZoomScale = (self.boundingMask == RMMapMinWidthBound ? self.bounds.size.width : self.bounds.size.height) / ((CATiledLayer *)tiledLayerView.layer).tileSize.width;
if (mapScrollView.minimumZoomScale > 0 && newMinZoomScale > mapScrollView.minimumZoomScale)
{
RMLog(@"clamping min zoom of %f to %f due to %@", log2f(mapScrollView.minimumZoomScale), log2f(newMinZoomScale), (self.boundingMask == RMMapMinWidthBound ? @"RMMapMinWidthBound" : @"RMMapMinHeightBound"));
mapScrollView.minimumZoomScale = newMinZoomScale;
}
}
}
- (RMProjectedRect)projectedBounds
{
CGPoint bottomLeft = CGPointMake(mapScrollView.contentOffset.x, mapScrollView.contentSize.height - (mapScrollView.contentOffset.y + mapScrollView.bounds.size.height));
... ... @@ -1277,6 +1302,8 @@
// RMLog(@"New minZoom:%f", newMinZoom);
mapScrollView.minimumZoomScale = exp2f(newMinZoom);
[self correctMinZoomScaleForBoundingMask];
}
- (void)setMaxZoom:(float)newMaxZoom
... ...
... ... @@ -150,8 +150,8 @@
DD2B375614CF8197008DE8CB /* RMMBTilesTileSource.m in Sources */ = {isa = PBXBuildFile; fileRef = DD2B375414CF8197008DE8CB /* RMMBTilesTileSource.m */; };
DD8CDB4A14E0507100B73EB9 /* RMMapQuestOSMSource.h in Headers */ = {isa = PBXBuildFile; fileRef = DD8CDB4814E0507100B73EB9 /* RMMapQuestOSMSource.h */; };
DD8CDB4B14E0507100B73EB9 /* RMMapQuestOSMSource.m in Sources */ = {isa = PBXBuildFile; fileRef = DD8CDB4914E0507100B73EB9 /* RMMapQuestOSMSource.m */; };
DD98B6FA14D76B930092882F /* RMTileStreamSource.h in Headers */ = {isa = PBXBuildFile; fileRef = DD98B6F814D76B930092882F /* RMTileStreamSource.h */; };
DD98B6FB14D76B930092882F /* RMTileStreamSource.m in Sources */ = {isa = PBXBuildFile; fileRef = DD98B6F914D76B930092882F /* RMTileStreamSource.m */; };
DD98B6FA14D76B930092882F /* RMMapBoxSource.h in Headers */ = {isa = PBXBuildFile; fileRef = DD98B6F814D76B930092882F /* RMMapBoxSource.h */; };
DD98B6FB14D76B930092882F /* RMMapBoxSource.m in Sources */ = {isa = PBXBuildFile; fileRef = DD98B6F914D76B930092882F /* RMMapBoxSource.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
... ... @@ -301,8 +301,8 @@
DD2B375414CF8197008DE8CB /* RMMBTilesTileSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMMBTilesTileSource.m; sourceTree = "<group>"; };
DD8CDB4814E0507100B73EB9 /* RMMapQuestOSMSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMMapQuestOSMSource.h; sourceTree = "<group>"; };
DD8CDB4914E0507100B73EB9 /* RMMapQuestOSMSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMMapQuestOSMSource.m; sourceTree = "<group>"; };
DD98B6F814D76B930092882F /* RMTileStreamSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMTileStreamSource.h; sourceTree = "<group>"; };
DD98B6F914D76B930092882F /* RMTileStreamSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMTileStreamSource.m; sourceTree = "<group>"; };
DD98B6F814D76B930092882F /* RMMapBoxSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMMapBoxSource.h; sourceTree = "<group>"; };
DD98B6F914D76B930092882F /* RMMapBoxSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMMapBoxSource.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
... ... @@ -366,8 +366,8 @@
16128CF4148D295300C23C0E /* RMOpenSeaMapSource.m */,
B83E64ED0E80E73F001663B6 /* RMOpenStreetMapSource.h */,
B83E64EE0E80E73F001663B6 /* RMOpenStreetMapSource.m */,
DD98B6F814D76B930092882F /* RMTileStreamSource.h */,
DD98B6F914D76B930092882F /* RMTileStreamSource.m */,
DD98B6F814D76B930092882F /* RMMapBoxSource.h */,
DD98B6F914D76B930092882F /* RMMapBoxSource.m */,
);
name = "Map sources";
sourceTree = "<group>";
... ... @@ -666,7 +666,7 @@
DD2B374F14CF814F008DE8CB /* FMDatabasePool.h in Headers */,
DD2B375114CF814F008DE8CB /* FMDatabaseQueue.h in Headers */,
DD2B375514CF8197008DE8CB /* RMMBTilesTileSource.h in Headers */,
DD98B6FA14D76B930092882F /* RMTileStreamSource.h in Headers */,
DD98B6FA14D76B930092882F /* RMMapBoxSource.h in Headers */,
DD8CDB4A14E0507100B73EB9 /* RMMapQuestOSMSource.h in Headers */,
1607499514E120A100D535F5 /* RMGenericMapSource.h in Headers */,
16FFF2CB14E3DBF700A170EC /* RMMapQuestOpenAerialSource.h in Headers */,
... ... @@ -883,7 +883,7 @@
DD2B375014CF814F008DE8CB /* FMDatabasePool.m in Sources */,
DD2B375214CF814F008DE8CB /* FMDatabaseQueue.m in Sources */,
DD2B375614CF8197008DE8CB /* RMMBTilesTileSource.m in Sources */,
DD98B6FB14D76B930092882F /* RMTileStreamSource.m in Sources */,
DD98B6FB14D76B930092882F /* RMMapBoxSource.m in Sources */,
DD8CDB4B14E0507100B73EB9 /* RMMapQuestOSMSource.m in Sources */,
1607499614E120A100D535F5 /* RMGenericMapSource.m in Sources */,
16FFF2CC14E3DBF700A170EC /* RMMapQuestOpenAerialSource.m in Sources */,
... ...