Authored by Thomas Rasch

o Show multiple tilesources as individual layers (addresses #51 and #47)

... ... @@ -6,6 +6,8 @@
// Copyright (c) 2011 Alpstein. All rights reserved.
//
#import "RMTileSource.h"
@class RMMapView, RMMapTiledLayerView;
@protocol RMMapTiledLayerViewDelegate <NSObject>
... ... @@ -21,15 +23,11 @@
@end
@interface RMMapTiledLayerView : UIView
{
id <RMMapTiledLayerViewDelegate> delegate;
RMMapView *mapView;
}
@property (nonatomic, assign) id <RMMapTiledLayerViewDelegate> delegate;
@property (nonatomic, assign) BOOL useSnapshotRenderer;
- (id)initWithFrame:(CGRect)frame mapView:(RMMapView *)aMapView;
- (id)initWithFrame:(CGRect)frame mapView:(RMMapView *)aMapView forTileSource:(id <RMTileSource>)aTileSource;
@end
... ...
... ... @@ -20,6 +20,10 @@
@end
@implementation RMMapTiledLayerView
{
RMMapView *mapView;
id <RMTileSource> tileSource;
}
@synthesize delegate;
@synthesize useSnapshotRenderer;
... ... @@ -34,12 +38,13 @@
return (CATiledLayer *)self.layer;
}
- (id)initWithFrame:(CGRect)frame mapView:(RMMapView *)aMapView
- (id)initWithFrame:(CGRect)frame mapView:(RMMapView *)aMapView forTileSource:(id <RMTileSource>)aTileSource
{
if (!(self = [super initWithFrame:frame]))
return nil;
mapView = [aMapView retain];
tileSource = [aTileSource retain];
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = YES;
... ... @@ -48,7 +53,7 @@
self.useSnapshotRenderer = NO;
CATiledLayer *tiledLayer = [self tiledLayer];
size_t levelsOf2xMagnification = mapView.tileSource.maxZoom;
size_t levelsOf2xMagnification = mapView.tileSourcesContainer.maxZoom;
if (mapView.adjustTilesForRetinaDisplay) levelsOf2xMagnification += 1;
tiledLayer.levelsOfDetail = levelsOf2xMagnification;
tiledLayer.levelsOfDetailBias = levelsOf2xMagnification;
... ... @@ -80,7 +85,8 @@
- (void)dealloc
{
[[mapView tileSource] cancelAllDownloads];
[tileSource cancelAllDownloads];
[tileSource release]; tileSource = nil;
[mapView release]; mapView = nil;
[super dealloc];
}
... ... @@ -118,7 +124,7 @@
{
for (int y=y1; y<=y2; ++y)
{
UIImage *tileImage = [[mapView tileSource] imageForTile:RMTileMake(x, y, zoom) inCache:[mapView tileCache]];
UIImage *tileImage = [tileSource imageForTile:RMTileMake(x, y, zoom) inCache:[mapView tileCache]];
[tileImage drawInRect:CGRectMake(x * rectSize, y * rectSize, rectSize, rectSize)];
}
}
... ... @@ -134,7 +140,7 @@
UIGraphicsPushContext(context);
UIImage *tileImage = [[mapView tileSource] imageForTile:RMTileMake(x, y, zoom) inCache:[mapView tileCache]];
UIImage *tileImage = [tileSource imageForTile:RMTileMake(x, y, zoom) inCache:[mapView tileCache]];
if ( ! tileImage)
{
... ... @@ -147,14 +153,14 @@
NSUInteger currentTileDepth = 1, currentZoom = zoom - currentTileDepth;
// tries to return lower zoom level tiles if a tile cannot be found
while ( !tileImage && currentZoom >= mapView.tileSource.minZoom && currentTileDepth <= mapView.missingTilesDepth)
while ( !tileImage && currentZoom >= mapView.tileSourcesContainer.minZoom && currentTileDepth <= mapView.missingTilesDepth)
{
float nextX = x / powf(2.0, (float)currentTileDepth),
nextY = y / powf(2.0, (float)currentTileDepth);
float nextTileX = floor(nextX),
nextTileY = floor(nextY);
tileImage = [[mapView tileSource] imageForTile:RMTileMake((int)nextTileX, (int)nextTileY, currentZoom) inCache:[mapView tileCache]];
tileImage = [tileSource imageForTile:RMTileMake((int)nextTileX, (int)nextTileY, currentZoom) inCache:[mapView tileCache]];
if (tileImage)
{
... ...
... ... @@ -36,6 +36,7 @@
#import "RMMapOverlayView.h"
#import "RMMapTiledLayerView.h"
#import "RMMapScrollView.h"
#import "RMTileSourcesContainer.h"
// constants for boundingMask
enum {
... ... @@ -74,7 +75,6 @@ typedef enum {
UIView *backgroundView;
RMMapScrollView *mapScrollView;
RMMapTiledLayerView *tiledLayerView;
RMMapOverlayView *overlayView;
double metersPerPixel;
... ... @@ -86,7 +86,6 @@ typedef enum {
BOOL enableClustering, positionClusterMarkersAtTheGravityCenter;
CGSize clusterMarkerSize, clusterAreaSize;
id <RMTileSource> tileSource;
RMTileCache *tileCache; // Generic tile cache
float minZoom, maxZoom, zoom;
... ... @@ -138,14 +137,13 @@ typedef enum {
@property (nonatomic, readonly) RMProjection *projection;
@property (nonatomic, readonly) id <RMMercatorToTileProjection> mercatorToTileProjection;
@property (nonatomic, retain) id <RMTileSource> tileSource;
@property (nonatomic, retain) RMTileCache *tileCache;
@property (nonatomic, readonly) RMTileSourcesContainer *tileSourcesContainer;
/// subview for the background image displayed while tiles are loading.
@property (nonatomic, retain) UIView *backgroundView;
#pragma mark -
#pragma mark Initializers
#pragma mark - Initializers
- (id)initWithFrame:(CGRect)frame andTilesource:(id <RMTileSource>)newTilesource;
... ... @@ -160,8 +158,7 @@ typedef enum {
- (void)setFrame:(CGRect)frame;
#pragma mark -
#pragma mark Movement
#pragma mark - Movement
/// recenter the map on #coordinate, expressed as CLLocationCoordinate2D (latitude/longitude)
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated;
... ... @@ -171,8 +168,7 @@ typedef enum {
- (void)moveBy:(CGSize)delta;
#pragma mark -
#pragma mark Zoom
#pragma mark - Zoom
/// recenter the map on #boundsRect, expressed in projected meters
- (void)setProjectedBounds:(RMProjectedRect)boundsRect animated:(BOOL)animated;
... ... @@ -189,8 +185,7 @@ typedef enum {
- (void)setMetersPerPixel:(double)newMetersPerPixel animated:(BOOL)animated;
#pragma mark -
#pragma mark Conversions
#pragma mark - Conversions
- (CGPoint)projectedPointToPixel:(RMProjectedPoint)projectedPoint;
- (CGPoint)coordinateToPixel:(CLLocationCoordinate2D)coordinate;
... ... @@ -212,16 +207,14 @@ typedef enum {
/// returns the smallest bounding box containing a rectangular region of the view
- (RMSphericalTrapezium)latitudeLongitudeBoundingBoxFor:(CGRect) rect;
#pragma mark -
#pragma mark Bounds
#pragma mark - Bounds
- (BOOL)tileSourceBoundsContainProjectedPoint:(RMProjectedPoint)point;
- (void)setConstraintsSouthWest:(CLLocationCoordinate2D)southWest northEast:(CLLocationCoordinate2D)northEast;
- (void)setProjectedConstraintsSouthWest:(RMProjectedPoint)southWest northEast:(RMProjectedPoint)northEast;
#pragma mark -
#pragma mark Annotations
#pragma mark - Annotations
- (NSArray *)annotations;
... ... @@ -234,14 +227,27 @@ typedef enum {
- (CGPoint)mapPositionForAnnotation:(RMAnnotation *)annotation;
#pragma mark -
#pragma mark Cache
#pragma mark - TileSources
- (id <RMTileSource>)tileSource; // the first tile source, for backwards compatibility
- (NSArray *)tileSources;
- (BOOL)setTileSource:(id <RMTileSource>)tileSource; // replaces all tilesources with the new tilesource
- (BOOL)addTileSource:(id <RMTileSource>)tileSource;
- (BOOL)addTileSource:(id<RMTileSource>)tileSource atIndex:(NSUInteger)index;
- (void)removeTileSource:(id <RMTileSource>)tileSource;
- (void)removeTileSourceAtIndex:(NSUInteger)index;
- (void)moveTileSourceAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex;
#pragma mark - Cache
/// Clear all images from the #tileSource's caching system.
-(void)removeAllCachedImages;
#pragma mark -
#pragma mark Snapshots
#pragma mark - Snapshots
- (UIImage *)takeSnapshot;
- (UIImage *)takeSnapshotAndIncludeOverlay:(BOOL)includeOverlay;
... ...
... ... @@ -97,6 +97,9 @@
BOOL _delegateHasWillHideLayerForAnnotation;
BOOL _delegateHasDidHideLayerForAnnotation;
RMTileSourcesContainer *_tileSourcesContainer;
UIView *_tiledLayersSuperview;
BOOL _constrainMovement;
RMProjectedRect _constrainingProjectedBounds;
... ... @@ -134,11 +137,12 @@
self.backgroundColor = [UIColor grayColor];
tileSource = nil;
_tileSourcesContainer = [RMTileSourcesContainer new];
_tiledLayersSuperview = nil;
projection = nil;
mercatorToTileProjection = nil;
mapScrollView = nil;
tiledLayerView = nil;
overlayView = nil;
screenScale = [UIScreen mainScreen].scale;
... ... @@ -174,7 +178,7 @@
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
RMLog(@"Map initialised. tileSource:%@, minZoom:%f, maxZoom:%f, zoom:%f at {%f,%f}", tileSource, [self minZoom], [self maxZoom], [self zoom], [self centerCoordinate].longitude, [self centerCoordinate].latitude);
RMLog(@"Map initialised. tileSource:%@, minZoom:%f, maxZoom:%f, zoom:%f at {%f,%f}", newTilesource, [self minZoom], [self maxZoom], [self zoom], [self centerCoordinate].longitude, [self centerCoordinate].latitude);
}
- (id)initWithCoder:(NSCoder *)aDecoder
... ... @@ -277,11 +281,11 @@
[annotations release]; annotations = nil;
[visibleAnnotations release]; visibleAnnotations = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
[tiledLayerView release]; tiledLayerView = nil;
[mapScrollView removeObserver:self forKeyPath:@"contentOffset"];
[_tiledLayersSuperview release]; _tiledLayersSuperview = nil;
[mapScrollView release]; mapScrollView = nil;
[overlayView release]; overlayView = nil;
[tileSource cancelAllDownloads]; [tileSource release]; tileSource = nil;
[_tileSourcesContainer cancelAllDownloads]; [_tileSourcesContainer release]; _tileSourcesContainer = nil;
[projection release]; projection = nil;
[mercatorToTileProjection release]; mercatorToTileProjection = nil;
[self setTileCache:nil];
... ... @@ -292,7 +296,7 @@
{
LogMethod();
[tileSource didReceiveMemoryWarning];
[_tileSourcesContainer didReceiveMemoryWarning];
[tileCache didReceiveMemoryWarning];
}
... ... @@ -436,7 +440,7 @@
- (BOOL)tileSourceBoundsContainProjectedPoint:(RMProjectedPoint)point
{
RMSphericalTrapezium bounds = [self.tileSource latitudeLongitudeBoundingBox];
RMSphericalTrapezium bounds = [self.tileSourcesContainer latitudeLongitudeBoundingBox];
if (bounds.northEast.latitude == 90 && bounds.northEast.longitude == 180 &&
bounds.southWest.latitude == -90 && bounds.southWest.longitude == -180)
... ... @@ -565,7 +569,10 @@
{
if (self.boundingMask != RMMapNoMinBound)
{
CGFloat newMinZoomScale = (self.boundingMask == RMMapMinWidthBound ? self.bounds.size.width : self.bounds.size.height) / ((CATiledLayer *)tiledLayerView.layer).tileSize.width;
if ([_tiledLayersSuperview.subviews count] == 0)
return;
CGFloat newMinZoomScale = (self.boundingMask == RMMapMinWidthBound ? self.bounds.size.width : self.bounds.size.height) / ((CATiledLayer *)((RMMapTiledLayerView *)[_tiledLayersSuperview.subviews objectAtIndex:0]).layer).tileSize.width;
if (mapScrollView.minimumZoomScale > 0 && newMinZoomScale > mapScrollView.minimumZoomScale)
{
... ... @@ -941,15 +948,20 @@
{
[overlayView removeFromSuperview]; [overlayView release]; overlayView = nil;
tiledLayerView.layer.contents = nil;
[tiledLayerView removeFromSuperview]; [tiledLayerView release]; tiledLayerView = nil;
for (RMMapTiledLayerView *tiledLayerView in _tiledLayersSuperview.subviews)
{
tiledLayerView.layer.contents = nil;
[tiledLayerView removeFromSuperview]; [tiledLayerView release]; tiledLayerView = nil;
}
[_tiledLayersSuperview removeFromSuperview]; [_tiledLayersSuperview release]; _tiledLayersSuperview = nil;
[mapScrollView removeObserver:self forKeyPath:@"contentOffset"];
[mapScrollView removeFromSuperview]; [mapScrollView release]; mapScrollView = nil;
_mapScrollViewIsZooming = NO;
int tileSideLength = [[self tileSource] tileSideLength];
int tileSideLength = [_tileSourcesContainer tileSideLength];
CGSize contentSize = CGSizeMake(tileSideLength, tileSideLength); // zoom level 1
mapScrollView = [[RMMapScrollView alloc] initWithFrame:[self bounds]];
... ... @@ -967,15 +979,22 @@
mapScrollView.maximumZoomScale = exp2f([self maxZoom]);
mapScrollView.contentOffset = CGPointMake(0.0, 0.0);
tiledLayerView = [[RMMapTiledLayerView alloc] initWithFrame:CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) mapView:self];
tiledLayerView.delegate = self;
_tiledLayersSuperview = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, contentSize.width, contentSize.height)];
if (self.adjustTilesForRetinaDisplay && screenScale > 1.0)
((CATiledLayer *)tiledLayerView.layer).tileSize = CGSizeMake(tileSideLength * 2.0, tileSideLength * 2.0);
else
((CATiledLayer *)tiledLayerView.layer).tileSize = CGSizeMake(tileSideLength, tileSideLength);
for (id <RMTileSource> tileSource in _tileSourcesContainer.tileSources)
{
RMMapTiledLayerView *tiledLayerView = [[RMMapTiledLayerView alloc] initWithFrame:CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) mapView:self forTileSource:tileSource];
tiledLayerView.delegate = self;
[mapScrollView addSubview:tiledLayerView];
if (self.adjustTilesForRetinaDisplay && screenScale > 1.0)
((CATiledLayer *)tiledLayerView.layer).tileSize = CGSizeMake(tileSideLength * 2.0, tileSideLength * 2.0);
else
((CATiledLayer *)tiledLayerView.layer).tileSize = CGSizeMake(tileSideLength, tileSideLength);
[_tiledLayersSuperview addSubview:tiledLayerView];
}
[mapScrollView addSubview:_tiledLayersSuperview];
_lastZoom = [self zoom];
_lastContentOffset = mapScrollView.contentOffset;
... ... @@ -1005,7 +1024,7 @@
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return tiledLayerView;
return _tiledLayersSuperview;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
... ... @@ -1084,7 +1103,7 @@
}
else
{
[self mapTiledLayerView:tiledLayerView doubleTapAtPoint:aPoint];
[self mapTiledLayerView:[_tiledLayersSuperview.subviews lastObject] doubleTapAtPoint:aPoint];
}
}
... ... @@ -1117,7 +1136,7 @@
}
else
{
[self mapTiledLayerView:tiledLayerView doubleTapAtPoint:aPoint];
[self mapTiledLayerView:[_tiledLayersSuperview.subviews lastObject] doubleTapAtPoint:aPoint];
}
}
... ... @@ -1318,9 +1337,13 @@
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, [[UIScreen mainScreen] scale]);
tiledLayerView.useSnapshotRenderer = YES;
for (RMMapTiledLayerView *tiledLayerView in _tiledLayersSuperview.subviews)
tiledLayerView.useSnapshotRenderer = YES;
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
tiledLayerView.useSnapshotRenderer = NO;
for (RMMapTiledLayerView *tiledLayerView in _tiledLayersSuperview.subviews)
tiledLayerView.useSnapshotRenderer = NO;
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
... ... @@ -1336,32 +1359,56 @@
return [self takeSnapshotAndIncludeOverlay:YES];
}
#pragma mark -
#pragma mark Properties
#pragma mark - TileSources
- (RMTileSourcesContainer *)tileSourcesContainer
{
return [[_tileSourcesContainer retain] autorelease];
}
- (id <RMTileSource>)tileSource
{
return [[tileSource retain] autorelease];
NSArray *tileSources = [_tileSourcesContainer tileSources];
if ([tileSources count] > 0)
return [tileSources objectAtIndex:0];
return nil;
}
- (void)setTileSource:(id <RMTileSource>)newTileSource
- (NSArray *)tileSources
{
if (tileSource == newTileSource)
return;
return [_tileSourcesContainer tileSources];
}
RMProjectedPoint centerPoint = [self centerProjectedPoint];
- (BOOL)setTileSource:(id <RMTileSource>)tileSource
{
[_tileSourcesContainer removeAllTileSources];
return [self addTileSource:tileSource];
}
- (BOOL)addTileSource:(id <RMTileSource>)tileSource
{
return [self addTileSource:tileSource atIndex:-1];
}
[tileSource cancelAllDownloads];
[tileSource autorelease];
tileSource = [newTileSource retain];
- (BOOL)addTileSource:(id<RMTileSource>)newTileSource atIndex:(NSUInteger)index
{
if ([_tileSourcesContainer.tileSources containsObject:newTileSource])
return YES;
if ( ! [_tileSourcesContainer addTileSource:newTileSource atIndex:index])
return NO;
RMProjectedPoint centerPoint = [self centerProjectedPoint];
[projection release];
projection = [[tileSource projection] retain];
projection = [[_tileSourcesContainer projection] retain];
[mercatorToTileProjection release];
mercatorToTileProjection = [[tileSource mercatorToTileProjection] retain];
mercatorToTileProjection = [[_tileSourcesContainer mercatorToTileProjection] retain];
RMSphericalTrapezium bounds = [tileSource latitudeLongitudeBoundingBox];
RMSphericalTrapezium bounds = [_tileSourcesContainer latitudeLongitudeBoundingBox];
_constrainMovement = !(bounds.northEast.latitude == 90.0 && bounds.northEast.longitude == 180.0 && bounds.southWest.latitude == -90.0 && bounds.southWest.longitude == -180.0);
... ... @@ -1370,16 +1417,70 @@
else
_constrainingProjectedBounds = projection.planetBounds;
[self setMinZoom:newTileSource.minZoom];
[self setMaxZoom:newTileSource.maxZoom];
[self setMinZoom:_tileSourcesContainer.minZoom];
[self setMaxZoom:_tileSourcesContainer.maxZoom];
[self setZoom:[self zoom]]; // setZoom clamps zoom level to min/max limits
// Recreate the map layer
[self createMapView];
[self setCenterProjectedPoint:centerPoint animated:NO];
return YES;
}
- (void)removeTileSource:(id <RMTileSource>)tileSource
{
RMProjectedPoint centerPoint = [self centerProjectedPoint];
[_tileSourcesContainer removeTileSource:tileSource];
if ([_tileSourcesContainer.tileSources count] == 0)
{
[projection release];
[mercatorToTileProjection release];
_constrainMovement = NO;
}
// Recreate the map layer
[self createMapView];
[self setCenterProjectedPoint:centerPoint animated:NO];
}
- (void)removeTileSourceAtIndex:(NSUInteger)index
{
RMProjectedPoint centerPoint = [self centerProjectedPoint];
[_tileSourcesContainer removeTileSourceAtIndex:index];
if ([_tileSourcesContainer.tileSources count] == 0)
{
[projection release];
[mercatorToTileProjection release];
_constrainMovement = NO;
}
// Recreate the map layer
[self createMapView];
[self setCenterProjectedPoint:centerPoint animated:NO];
}
- (void)moveTileSourceAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex
{
RMProjectedPoint centerPoint = [self centerProjectedPoint];
[_tileSourcesContainer moveTileSourceAtIndex:fromIndex toIndex:toIndex];
// Recreate the map layer
[self createMapView];
[self setCenterProjectedPoint:centerPoint animated:NO];
}
#pragma mark - Properties
- (UIView *)backgroundView
{
return [[backgroundView retain] autorelease];
... ...
//
// RMOpenSeaMapLayer.h
//
// Copyright (c) 2008-2012, Route-Me Contributors
// 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 "RMAbstractWebMapSource.h"
/*!
\brief Subclass of RMAbstractMercatorWebSource for access to the OpenSeaMap Layer over OpenStreetMap.
Provides key-based access to tiles from the OpenSeaMap layer.
*/
@interface RMOpenSeaMapLayer : RMAbstractWebMapSource
@end
... ...
//
// RMOpenSeaMapLayer.m
//
// Copyright (c) 2008-2012, Route-Me Contributors
// 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 "RMOpenSeaMapLayer.h"
@implementation RMOpenSeaMapLayer
- (id)init
{
if (!(self = [super init]))
return nil;
// http://wiki.openstreetmap.org/index.php/FAQ#What_is_the_map_scale_for_a_particular_zoom_level_of_the_map.3F
[self setMaxZoom:18];
[self setMinZoom:1];
return self;
}
- (NSArray *)URLsForTile:(RMTile)tile
{
NSAssert4(((tile.zoom >= self.minZoom) && (tile.zoom <= self.maxZoom)),
@"%@ tried to retrieve tile with zoomLevel %d, outside source's defined range %f to %f",
self, tile.zoom, self.minZoom, self.maxZoom);
return [NSArray arrayWithObject:[NSURL URLWithString:[NSString stringWithFormat:@"http://tiles.openseamap.org/seamark/%d/%d/%d.png", tile.zoom, tile.x, tile.y]]];
}
- (NSString *)uniqueTilecacheKey
{
return @"OpenSeaMapLayer";
}
- (NSString *)shortName
{
return @"Open Sea Map";
}
- (NSString *)longDescription
{
return @"Open Sea Map/Open Street Map, the free wiki world map, provides freely usable map data for all parts of the world, under the Creative Commons Attribution-Share Alike 2.0 license.";
}
- (NSString *)shortAttribution
{
return @"© OpenStreetMap CC-BY-SA";
}
- (NSString *)longAttribution
{
return @"Map data © OpenStreetMap, licensed under Creative Commons Share Alike By Attribution.";
}
@end
... ...
//
// RMTileSourcesContainer.h
// MapView
//
// Created by Thomas Rasch on 21.06.12.
// Copyright (c) 2012 Alpstein. All rights reserved.
//
#import "RMTileSource.h"
@interface RMTileSourcesContainer : NSObject
- (NSArray *)tileSources;
- (BOOL)setTileSource:(id <RMTileSource>)tileSource;
- (BOOL)addTileSource:(id <RMTileSource>)tileSource;
- (BOOL)addTileSource:(id<RMTileSource>)tileSource atIndex:(NSUInteger)index;
- (void)removeTileSource:(id <RMTileSource>)tileSource;
- (void)removeTileSourceAtIndex:(NSUInteger)index;
- (void)moveTileSourceAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex;
- (void)removeAllTileSources;
- (void)cancelAllDownloads;
- (RMFractalTileProjection *)mercatorToTileProjection;
- (RMProjection *)projection;
- (float)minZoom;
- (float)maxZoom;
- (int)tileSideLength;
- (RMSphericalTrapezium)latitudeLongitudeBoundingBox;
- (void)didReceiveMemoryWarning;
@end
... ...
//
// RMTileSourcesContainer.m
// MapView
//
// Created by Thomas Rasch on 21.06.12.
// Copyright (c) 2012 Alpstein. All rights reserved.
//
#import "RMTileSourcesContainer.h"
@implementation RMTileSourcesContainer
{
NSMutableArray *_tileSources;
RMProjection *_projection;
RMFractalTileProjection *_mercatorToTileProjection;
RMSphericalTrapezium _latitudeLongitudeBoundingBox;
float _minZoom, _maxZoom;
int _tileSideLength;
}
- (id)init
{
if (!(self = [super init]))
return nil;
_tileSources = [NSMutableArray new];
_projection = nil;
_mercatorToTileProjection = nil;
_latitudeLongitudeBoundingBox = ((RMSphericalTrapezium) {
.northEast = {.latitude = 90.0, .longitude = 180.0},
.southWest = {.latitude = -90.0, .longitude = -180.0}
});
_minZoom = FLT_MIN;
_maxZoom = FLT_MAX;
_tileSideLength = 0;
return self;
}
- (void)dealloc
{
[_tileSources release]; _tileSources = nil;
[_projection release]; _projection = nil;
[_mercatorToTileProjection release]; _mercatorToTileProjection = nil;
[super dealloc];
}
#pragma mark -
- (NSArray *)tileSources
{
return [[_tileSources copy] autorelease];
}
- (BOOL)setTileSource:(id <RMTileSource>)tileSource
{
[self removeAllTileSources];
return [self addTileSource:tileSource];
}
- (BOOL)addTileSource:(id <RMTileSource>)tileSource
{
return [self addTileSource:tileSource atIndex:-1];
}
- (BOOL)addTileSource:(id<RMTileSource>)tileSource atIndex:(NSUInteger)index
{
RMProjection *newProjection = [tileSource projection];
RMFractalTileProjection *newFractalTileProjection = [tileSource mercatorToTileProjection];
if ( ! _projection)
{
_projection = [newProjection retain];
}
else if (_projection != newProjection)
{
NSLog(@"The tilesource '%@' has a different projection than the tilesource container", [tileSource shortName]);
return NO;
}
if ( ! _mercatorToTileProjection)
_mercatorToTileProjection = [newFractalTileProjection retain];
_minZoom = MAX(_minZoom, [tileSource minZoom]);
_maxZoom = MIN(_maxZoom, [tileSource maxZoom]);
if (_tileSideLength == 0)
{
_tileSideLength = [tileSource tileSideLength];
}
else if (_tileSideLength != [tileSource tileSideLength])
{
NSLog(@"The tilesource '%@' has a different tile side length than the tilesource container", [tileSource shortName]);
return NO;
}
RMSphericalTrapezium newLatitudeLongitudeBoundingBox = [tileSource latitudeLongitudeBoundingBox];
_latitudeLongitudeBoundingBox = ((RMSphericalTrapezium) {
.northEast = {
.latitude = MIN(_latitudeLongitudeBoundingBox.northEast.latitude, newLatitudeLongitudeBoundingBox.northEast.latitude),
.longitude = MIN(_latitudeLongitudeBoundingBox.northEast.longitude, newLatitudeLongitudeBoundingBox.northEast.longitude)},
.southWest = {
.latitude = MAX(_latitudeLongitudeBoundingBox.southWest.latitude, newLatitudeLongitudeBoundingBox.southWest.latitude),
.longitude = MAX(_latitudeLongitudeBoundingBox.southWest.longitude, newLatitudeLongitudeBoundingBox.southWest.longitude)
}
});
if (index >= [_tileSources count])
[_tileSources addObject:tileSource];
else
[_tileSources insertObject:tileSource atIndex:index];
RMLog(@"Added the tilesource '%@' to the container", [tileSource shortName]);
return YES;
}
- (void)removeTileSource:(id <RMTileSource>)tileSource
{
[tileSource cancelAllDownloads];
[_tileSources removeObject:tileSource];
RMLog(@"Removed the tilesource '%@' from the container", [tileSource shortName]);
if ([_tileSources count] == 0)
{
[self removeAllTileSources]; // cleanup
}
}
- (void)removeTileSourceAtIndex:(NSUInteger)index
{
if (index >= [_tileSources count])
return;
id <RMTileSource> tileSource = [_tileSources objectAtIndex:index];
[tileSource cancelAllDownloads];
[_tileSources removeObject:tileSource];
RMLog(@"Removed the tilesource '%@' from the container", [tileSource shortName]);
}
- (void)moveTileSourceAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex
{
if (fromIndex == toIndex)
return;
if (fromIndex >= [_tileSources count])
return;
id tileSource = [[_tileSources objectAtIndex:fromIndex] retain];
[_tileSources removeObjectAtIndex:fromIndex];
if (toIndex >= [_tileSources count])
[_tileSources addObject:tileSource];
else
[_tileSources insertObject:tileSource atIndex:toIndex];
[tileSource autorelease];
}
- (void)removeAllTileSources
{
[self cancelAllDownloads];
[_tileSources removeAllObjects];
if ([_tileSources count] == 0)
{
[_projection release]; _projection = nil;
[_mercatorToTileProjection release]; _mercatorToTileProjection = nil;
_latitudeLongitudeBoundingBox = ((RMSphericalTrapezium) {
.northEast = {.latitude = 90.0, .longitude = 180.0},
.southWest = {.latitude = -90.0, .longitude = -180.0}
});
_minZoom = FLT_MIN;
_maxZoom = FLT_MAX;
_tileSideLength = 0;
}
}
- (void)cancelAllDownloads
{
for (id <RMTileSource>tileSource in _tileSources)
[tileSource cancelAllDownloads];
}
- (RMFractalTileProjection *)mercatorToTileProjection
{
return _mercatorToTileProjection;
}
- (RMProjection *)projection
{
return _projection;
}
- (float)minZoom
{
return _minZoom;
}
- (float)maxZoom
{
return _maxZoom;
}
- (int)tileSideLength
{
return _tileSideLength;
}
- (RMSphericalTrapezium)latitudeLongitudeBoundingBox
{
return _latitudeLongitudeBoundingBox;
}
- (void)didReceiveMemoryWarning
{
for (id <RMTileSource>tileSource in _tileSources)
[tileSource didReceiveMemoryWarning];
}
@end
... ...
... ... @@ -45,6 +45,8 @@
160EEDB013D41DEC007C5501 /* RMAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 160EEDAE13D41DEC007C5501 /* RMAnnotation.m */; };
16128CF5148D295300C23C0E /* RMOpenSeaMapSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 16128CF3148D295300C23C0E /* RMOpenSeaMapSource.h */; };
16128CF6148D295300C23C0E /* RMOpenSeaMapSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 16128CF4148D295300C23C0E /* RMOpenSeaMapSource.m */; };
161E563A1594664E00B00BB6 /* RMOpenSeaMapLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 161E56381594664E00B00BB6 /* RMOpenSeaMapLayer.h */; };
161E563B1594664E00B00BB6 /* RMOpenSeaMapLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 161E56391594664E00B00BB6 /* RMOpenSeaMapLayer.m */; };
16EC85D2133CA6C300219947 /* RMAbstractMercatorTileSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 16EC85CC133CA6C300219947 /* RMAbstractMercatorTileSource.h */; };
16EC85D3133CA6C300219947 /* RMAbstractMercatorTileSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 16EC85CD133CA6C300219947 /* RMAbstractMercatorTileSource.m */; };
16EC85D4133CA6C300219947 /* RMAbstractWebMapSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 16EC85CE133CA6C300219947 /* RMAbstractWebMapSource.h */; };
... ... @@ -57,6 +59,8 @@
16F98C971590CFF000FF90CE /* RMShape.m in Sources */ = {isa = PBXBuildFile; fileRef = 16F98C951590CFF000FF90CE /* RMShape.m */; };
16FAB66413E03D55002F4E1C /* RMQuadTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 16FAB66213E03D55002F4E1C /* RMQuadTree.h */; };
16FAB66513E03D55002F4E1C /* RMQuadTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 16FAB66313E03D55002F4E1C /* RMQuadTree.m */; };
16FBF07615936BF1004ECAD1 /* RMTileSourcesContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 16FBF07415936BF1004ECAD1 /* RMTileSourcesContainer.h */; };
16FBF07715936BF1004ECAD1 /* RMTileSourcesContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 16FBF07515936BF1004ECAD1 /* RMTileSourcesContainer.m */; };
16FFF2CB14E3DBF700A170EC /* RMMapQuestOpenAerialSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 16FFF2C914E3DBF700A170EC /* RMMapQuestOpenAerialSource.h */; };
16FFF2CC14E3DBF700A170EC /* RMMapQuestOpenAerialSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 16FFF2CA14E3DBF700A170EC /* RMMapQuestOpenAerialSource.m */; };
17F02BB11319BA4B00260C6B /* RouteMe.h in Headers */ = {isa = PBXBuildFile; fileRef = 17F02BB01319BA4B00260C6B /* RouteMe.h */; };
... ... @@ -198,6 +202,8 @@
160EEDAE13D41DEC007C5501 /* RMAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMAnnotation.m; sourceTree = "<group>"; };
16128CF3148D295300C23C0E /* RMOpenSeaMapSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMOpenSeaMapSource.h; sourceTree = "<group>"; };
16128CF4148D295300C23C0E /* RMOpenSeaMapSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMOpenSeaMapSource.m; sourceTree = "<group>"; };
161E56381594664E00B00BB6 /* RMOpenSeaMapLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMOpenSeaMapLayer.h; sourceTree = "<group>"; };
161E56391594664E00B00BB6 /* RMOpenSeaMapLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMOpenSeaMapLayer.m; sourceTree = "<group>"; };
16EC85CC133CA6C300219947 /* RMAbstractMercatorTileSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMAbstractMercatorTileSource.h; sourceTree = "<group>"; };
16EC85CD133CA6C300219947 /* RMAbstractMercatorTileSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMAbstractMercatorTileSource.m; sourceTree = "<group>"; };
16EC85CE133CA6C300219947 /* RMAbstractWebMapSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMAbstractWebMapSource.h; sourceTree = "<group>"; };
... ... @@ -210,6 +216,8 @@
16F98C951590CFF000FF90CE /* RMShape.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMShape.m; sourceTree = "<group>"; };
16FAB66213E03D55002F4E1C /* RMQuadTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMQuadTree.h; sourceTree = "<group>"; };
16FAB66313E03D55002F4E1C /* RMQuadTree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMQuadTree.m; sourceTree = "<group>"; };
16FBF07415936BF1004ECAD1 /* RMTileSourcesContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMTileSourcesContainer.h; sourceTree = "<group>"; };
16FBF07515936BF1004ECAD1 /* RMTileSourcesContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMTileSourcesContainer.m; sourceTree = "<group>"; };
16FFF2C914E3DBF700A170EC /* RMMapQuestOpenAerialSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMMapQuestOpenAerialSource.h; sourceTree = "<group>"; };
16FFF2CA14E3DBF700A170EC /* RMMapQuestOpenAerialSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMMapQuestOpenAerialSource.m; sourceTree = "<group>"; };
17F02BB01319BA4B00260C6B /* RouteMe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RouteMe.h; sourceTree = "<group>"; };
... ... @@ -372,6 +380,8 @@
1606C9FD13D86BA300547581 /* RMOpenCycleMapSource.m */,
16128CF3148D295300C23C0E /* RMOpenSeaMapSource.h */,
16128CF4148D295300C23C0E /* RMOpenSeaMapSource.m */,
161E56381594664E00B00BB6 /* RMOpenSeaMapLayer.h */,
161E56391594664E00B00BB6 /* RMOpenSeaMapLayer.m */,
B83E64ED0E80E73F001663B6 /* RMOpenStreetMapSource.h */,
B83E64EE0E80E73F001663B6 /* RMOpenStreetMapSource.m */,
DD98B6F814D76B930092882F /* RMMapBoxSource.h */,
... ... @@ -529,6 +539,8 @@
children = (
16EC85CB133CA69A00219947 /* Map sources */,
B83E64EC0E80E73F001663B6 /* RMTileSource.h */,
16FBF07415936BF1004ECAD1 /* RMTileSourcesContainer.h */,
16FBF07515936BF1004ECAD1 /* RMTileSourcesContainer.m */,
16EC85CC133CA6C300219947 /* RMAbstractMercatorTileSource.h */,
16EC85CD133CA6C300219947 /* RMAbstractMercatorTileSource.m */,
16EC85CE133CA6C300219947 /* RMAbstractWebMapSource.h */,
... ... @@ -684,6 +696,8 @@
16FFF2CB14E3DBF700A170EC /* RMMapQuestOpenAerialSource.h in Headers */,
16F3581B15864135003A3AD9 /* RMMapScrollView.h in Headers */,
16F98C961590CFF000FF90CE /* RMShape.h in Headers */,
16FBF07615936BF1004ECAD1 /* RMTileSourcesContainer.h in Headers */,
161E563A1594664E00B00BB6 /* RMOpenSeaMapLayer.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
... ... @@ -903,6 +917,8 @@
16FFF2CC14E3DBF700A170EC /* RMMapQuestOpenAerialSource.m in Sources */,
16F3581C15864135003A3AD9 /* RMMapScrollView.m in Sources */,
16F98C971590CFF000FF90CE /* RMShape.m in Sources */,
16FBF07715936BF1004ECAD1 /* RMTileSourcesContainer.m in Sources */,
161E563B1594664E00B00BB6 /* RMOpenSeaMapLayer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
... ...