PageRenderTime 62ms CodeModel.GetById 15ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 1ms

/MapView/Map/RMMBTilesTileSource.m

http://github.com/route-me/route-me
Objective C | 339 lines | 214 code | 92 blank | 33 comment | 22 complexity | 386c95b2559cbe72705e4a7bdb20a0d8 MD5 | raw file
  1//
  2//  RMMBTilesTileSource.m
  3//
  4//  Created by Justin R. Miller on 6/18/10.
  5//  Copyright 2010, Code Sorcery Workshop, LLC and Development Seed, Inc.
  6//  All rights reserved.
  7//  
  8//  Redistribution and use in source and binary forms, with or without
  9//  modification, are permitted provided that the following conditions are met:
 10//  
 11//      * Redistributions of source code must retain the above copyright
 12//        notice, this list of conditions and the following disclaimer.
 13//  
 14//      * Redistributions in binary form must reproduce the above copyright
 15//        notice, this list of conditions and the following disclaimer in the
 16//        documentation and/or other materials provided with the distribution.
 17//  
 18//      * Neither the names of Code Sorcery Workshop, LLC or Development Seed,
 19//        Inc., nor the names of its contributors may be used to endorse or
 20//        promote products derived from this software without specific prior
 21//        written permission.
 22//  
 23//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 24//  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 25//  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 26//  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 27//  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 28//  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 29//  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 30//  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 31//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 32//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 33//
 34
 35#import "RMMBTilesTileSource.h"
 36#import "RMTileImage.h"
 37#import "RMProjection.h"
 38#import "RMFractalTileProjection.h"
 39
 40#import "FMDatabase.h"
 41
 42@implementation RMMBTilesTileSource
 43
 44- (id)initWithTileSetURL:(NSURL *)tileSetURL
 45{
 46	if ( ! [super init])
 47		return nil;
 48	
 49	tileProjection = [[RMFractalTileProjection alloc] initFromProjection:[self projection] 
 50                                                          tileSideLength:kMBTilesDefaultTileSize 
 51                                                                 maxZoom:kMBTilesDefaultMaxTileZoom 
 52                                                                 minZoom:kMBTilesDefaultMinTileZoom];
 53	
 54    db = [[FMDatabase databaseWithPath:[tileSetURL relativePath]] retain];
 55    
 56    if ( ! [db open])
 57        return nil;
 58    
 59	return self;
 60}
 61
 62- (void)dealloc
 63{
 64	[tileProjection release];
 65    
 66    [db close];
 67    [db release];
 68    
 69	[super dealloc];
 70}
 71
 72- (int)tileSideLength
 73{
 74	return tileProjection.tileSideLength;
 75}
 76
 77- (void)setTileSideLength:(NSUInteger)aTileSideLength
 78{
 79	[tileProjection setTileSideLength:aTileSideLength];
 80}
 81
 82- (RMTileImage *)tileImage:(RMTile)tile
 83{
 84    NSAssert4(((tile.zoom >= self.minZoom) && (tile.zoom <= self.maxZoom)),
 85			  @"%@ tried to retrieve tile with zoomLevel %d, outside source's defined range %f to %f", 
 86			  self, tile.zoom, self.minZoom, self.maxZoom);
 87
 88    NSInteger zoom = tile.zoom;
 89    NSInteger x    = tile.x;
 90    NSInteger y    = pow(2, zoom) - tile.y - 1;
 91
 92    FMResultSet *results = [db executeQuery:@"select tile_data from tiles where zoom_level = ? and tile_column = ? and tile_row = ?", 
 93                               [NSNumber numberWithFloat:zoom], 
 94                               [NSNumber numberWithFloat:x], 
 95                               [NSNumber numberWithFloat:y]];
 96    
 97    if ([db hadError])
 98        return [RMTileImage dummyTile:tile];
 99    
100    [results next];
101    
102    NSData *data = [results dataForColumn:@"tile_data"];
103
104    RMTileImage *image;
105    
106    if ( ! data)
107        image = [RMTileImage dummyTile:tile];
108    
109    else
110        image = [RMTileImage imageForTile:tile withData:data];
111    
112    [results close];
113    
114    return image;
115}
116
117- (NSString *)tileURL:(RMTile)tile
118{
119    return nil;
120}
121
122- (NSString *)tileFile:(RMTile)tile
123{
124    return nil;
125}
126
127- (NSString *)tilePath
128{
129    return nil;
130}
131
132- (id <RMMercatorToTileProjection>)mercatorToTileProjection
133{
134	return [[tileProjection retain] autorelease];
135}
136
137- (RMProjection *)projection
138{
139	return [RMProjection googleProjection];
140}
141
142- (float)minZoom
143{
144    FMResultSet *results = [db executeQuery:@"select min(zoom_level) from tiles"];
145    
146    if ([db hadError])
147        return kMBTilesDefaultMinTileZoom;
148    
149    [results next];
150    
151    double minZoom = [results doubleForColumnIndex:0];
152    
153    [results close];
154    
155    return (float)minZoom;
156}
157
158- (float)maxZoom
159{
160    FMResultSet *results = [db executeQuery:@"select max(zoom_level) from tiles"];
161    
162    if ([db hadError])
163        return kMBTilesDefaultMaxTileZoom;
164
165    [results next];
166    
167    double maxZoom = [results doubleForColumnIndex:0];
168    
169    [results close];
170    
171    return (float)maxZoom;
172}
173
174- (void)setMinZoom:(NSUInteger)aMinZoom
175{
176    [tileProjection setMinZoom:aMinZoom];
177}
178
179- (void)setMaxZoom:(NSUInteger)aMaxZoom
180{
181    [tileProjection setMaxZoom:aMaxZoom];
182}
183
184- (RMSphericalTrapezium)latitudeLongitudeBoundingBox
185{
186    FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'bounds'"];
187    
188    if ([db hadError])
189        return kMBTilesDefaultLatLonBoundingBox;
190    
191    [results next];
192    
193    NSString *boundsString = [results stringForColumnIndex:0];
194    
195    [results close];
196    
197    if (boundsString)
198    {
199        NSArray *parts = [boundsString componentsSeparatedByString:@","];
200        
201        if ([parts count] == 4)
202        {
203            RMSphericalTrapezium bounds = {
204                .southwest = {
205                    .longitude = [[parts objectAtIndex:0] doubleValue],
206                    .latitude  = [[parts objectAtIndex:1] doubleValue],
207                },
208                .northeast = {
209                    .longitude = [[parts objectAtIndex:2] doubleValue],
210                    .latitude  = [[parts objectAtIndex:3] doubleValue],
211                },
212            };
213            
214            return bounds;
215        }
216    }
217    
218    return kMBTilesDefaultLatLonBoundingBox;
219}
220
221- (BOOL)coversFullWorld
222{
223    RMSphericalTrapezium ownBounds     = [self latitudeLongitudeBoundingBox];
224    RMSphericalTrapezium defaultBounds = kMBTilesDefaultLatLonBoundingBox;
225    
226    if (ownBounds.southwest.longitude <= defaultBounds.southwest.longitude + 10 && 
227        ownBounds.northeast.longitude >= defaultBounds.northeast.longitude - 10)
228        return YES;
229    
230    return NO;
231}
232
233- (RMMBTilesLayerType)layerType
234{
235    FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'type'"];
236    
237    if ([db hadError])
238        return RMMBTilesLayerTypeBaselayer;
239    
240    [results next];
241    
242    NSString *type = nil;
243    
244    if ([results hasAnotherRow])
245        type = [results stringForColumn:@"value"];
246    
247    [results close];
248    
249    return ([type isEqualToString:@"overlay"] ? RMMBTilesLayerTypeOverlay : RMMBTilesLayerTypeBaselayer);
250}
251
252- (NSString *)legend
253{
254    FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'legend'"];
255    
256    if ([db hadError])
257        return nil;
258    
259    [results next];
260    
261    NSString *legend = nil;
262    
263    if ([results hasAnotherRow])
264        legend = [results stringForColumn:@"value"];
265    
266    [results close];
267    
268    return legend;
269}
270
271- (void)didReceiveMemoryWarning
272{
273    NSLog(@"*** didReceiveMemoryWarning in %@", [self class]);
274}
275
276- (NSString *)uniqueTilecacheKey
277{
278    return [NSString stringWithFormat:@"MBTiles%@", [[db databasePath] lastPathComponent]];
279}
280
281- (NSString *)shortName
282{
283    FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'name'"];
284    
285    if ([db hadError])
286        return @"Unknown MBTiles";
287    
288    [results next];
289    
290    NSString *shortName = [results stringForColumnIndex:0];
291    
292    [results close];
293    
294    return shortName;
295}
296
297- (NSString *)longDescription
298{
299    FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'description'"];
300    
301    if ([db hadError])
302        return @"Unknown MBTiles description";
303    
304    [results next];
305    
306    NSString *description = [results stringForColumnIndex:0];
307    
308    [results close];
309    
310    return [NSString stringWithFormat:@"%@%@%@", [self shortName], ([[self shortName] length] && [description length] ? @" - " : @""), description];
311}
312
313- (NSString *)shortAttribution
314{
315    FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'attribution'"];
316    
317    if ([db hadError])
318        return @"Unknown MBTiles attribution";
319    
320    [results next];
321    
322    NSString *attribution = [results stringForColumnIndex:0];
323    
324    [results close];
325    
326    return attribution;
327}
328
329- (NSString *)longAttribution
330{
331    return [NSString stringWithFormat:@"%@%@%@", [self shortName], ([[self shortName] length] && [[self shortAttribution] length] ? @" - " : @""), [self shortAttribution]];
332}
333
334- (void)removeAllCachedImages
335{
336    NSLog(@"*** removeAllCachedImages in %@", [self class]);
337}
338
339@end