/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. #import "RMMBTilesTileSource.h"
  35. #import "RMTileImage.h"
  36. #import "RMProjection.h"
  37. #import "RMFractalTileProjection.h"
  38. #import "FMDatabase.h"
  39. @implementation RMMBTilesTileSource
  40. - (id)initWithTileSetURL:(NSURL *)tileSetURL
  41. {
  42. if ( ! [super init])
  43. return nil;
  44. tileProjection = [[RMFractalTileProjection alloc] initFromProjection:[self projection]
  45. tileSideLength:kMBTilesDefaultTileSize
  46. maxZoom:kMBTilesDefaultMaxTileZoom
  47. minZoom:kMBTilesDefaultMinTileZoom];
  48. db = [[FMDatabase databaseWithPath:[tileSetURL relativePath]] retain];
  49. if ( ! [db open])
  50. return nil;
  51. return self;
  52. }
  53. - (void)dealloc
  54. {
  55. [tileProjection release];
  56. [db close];
  57. [db release];
  58. [super dealloc];
  59. }
  60. - (int)tileSideLength
  61. {
  62. return tileProjection.tileSideLength;
  63. }
  64. - (void)setTileSideLength:(NSUInteger)aTileSideLength
  65. {
  66. [tileProjection setTileSideLength:aTileSideLength];
  67. }
  68. - (RMTileImage *)tileImage:(RMTile)tile
  69. {
  70. NSAssert4(((tile.zoom >= self.minZoom) && (tile.zoom <= self.maxZoom)),
  71. @"%@ tried to retrieve tile with zoomLevel %d, outside source's defined range %f to %f",
  72. self, tile.zoom, self.minZoom, self.maxZoom);
  73. NSInteger zoom = tile.zoom;
  74. NSInteger x = tile.x;
  75. NSInteger y = pow(2, zoom) - tile.y - 1;
  76. FMResultSet *results = [db executeQuery:@"select tile_data from tiles where zoom_level = ? and tile_column = ? and tile_row = ?",
  77. [NSNumber numberWithFloat:zoom],
  78. [NSNumber numberWithFloat:x],
  79. [NSNumber numberWithFloat:y]];
  80. if ([db hadError])
  81. return [RMTileImage dummyTile:tile];
  82. [results next];
  83. NSData *data = [results dataForColumn:@"tile_data"];
  84. RMTileImage *image;
  85. if ( ! data)
  86. image = [RMTileImage dummyTile:tile];
  87. else
  88. image = [RMTileImage imageForTile:tile withData:data];
  89. [results close];
  90. return image;
  91. }
  92. - (NSString *)tileURL:(RMTile)tile
  93. {
  94. return nil;
  95. }
  96. - (NSString *)tileFile:(RMTile)tile
  97. {
  98. return nil;
  99. }
  100. - (NSString *)tilePath
  101. {
  102. return nil;
  103. }
  104. - (id <RMMercatorToTileProjection>)mercatorToTileProjection
  105. {
  106. return [[tileProjection retain] autorelease];
  107. }
  108. - (RMProjection *)projection
  109. {
  110. return [RMProjection googleProjection];
  111. }
  112. - (float)minZoom
  113. {
  114. FMResultSet *results = [db executeQuery:@"select min(zoom_level) from tiles"];
  115. if ([db hadError])
  116. return kMBTilesDefaultMinTileZoom;
  117. [results next];
  118. double minZoom = [results doubleForColumnIndex:0];
  119. [results close];
  120. return (float)minZoom;
  121. }
  122. - (float)maxZoom
  123. {
  124. FMResultSet *results = [db executeQuery:@"select max(zoom_level) from tiles"];
  125. if ([db hadError])
  126. return kMBTilesDefaultMaxTileZoom;
  127. [results next];
  128. double maxZoom = [results doubleForColumnIndex:0];
  129. [results close];
  130. return (float)maxZoom;
  131. }
  132. - (void)setMinZoom:(NSUInteger)aMinZoom
  133. {
  134. [tileProjection setMinZoom:aMinZoom];
  135. }
  136. - (void)setMaxZoom:(NSUInteger)aMaxZoom
  137. {
  138. [tileProjection setMaxZoom:aMaxZoom];
  139. }
  140. - (RMSphericalTrapezium)latitudeLongitudeBoundingBox
  141. {
  142. FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'bounds'"];
  143. if ([db hadError])
  144. return kMBTilesDefaultLatLonBoundingBox;
  145. [results next];
  146. NSString *boundsString = [results stringForColumnIndex:0];
  147. [results close];
  148. if (boundsString)
  149. {
  150. NSArray *parts = [boundsString componentsSeparatedByString:@","];
  151. if ([parts count] == 4)
  152. {
  153. RMSphericalTrapezium bounds = {
  154. .southwest = {
  155. .longitude = [[parts objectAtIndex:0] doubleValue],
  156. .latitude = [[parts objectAtIndex:1] doubleValue],
  157. },
  158. .northeast = {
  159. .longitude = [[parts objectAtIndex:2] doubleValue],
  160. .latitude = [[parts objectAtIndex:3] doubleValue],
  161. },
  162. };
  163. return bounds;
  164. }
  165. }
  166. return kMBTilesDefaultLatLonBoundingBox;
  167. }
  168. - (BOOL)coversFullWorld
  169. {
  170. RMSphericalTrapezium ownBounds = [self latitudeLongitudeBoundingBox];
  171. RMSphericalTrapezium defaultBounds = kMBTilesDefaultLatLonBoundingBox;
  172. if (ownBounds.southwest.longitude <= defaultBounds.southwest.longitude + 10 &&
  173. ownBounds.northeast.longitude >= defaultBounds.northeast.longitude - 10)
  174. return YES;
  175. return NO;
  176. }
  177. - (RMMBTilesLayerType)layerType
  178. {
  179. FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'type'"];
  180. if ([db hadError])
  181. return RMMBTilesLayerTypeBaselayer;
  182. [results next];
  183. NSString *type = nil;
  184. if ([results hasAnotherRow])
  185. type = [results stringForColumn:@"value"];
  186. [results close];
  187. return ([type isEqualToString:@"overlay"] ? RMMBTilesLayerTypeOverlay : RMMBTilesLayerTypeBaselayer);
  188. }
  189. - (NSString *)legend
  190. {
  191. FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'legend'"];
  192. if ([db hadError])
  193. return nil;
  194. [results next];
  195. NSString *legend = nil;
  196. if ([results hasAnotherRow])
  197. legend = [results stringForColumn:@"value"];
  198. [results close];
  199. return legend;
  200. }
  201. - (void)didReceiveMemoryWarning
  202. {
  203. NSLog(@"*** didReceiveMemoryWarning in %@", [self class]);
  204. }
  205. - (NSString *)uniqueTilecacheKey
  206. {
  207. return [NSString stringWithFormat:@"MBTiles%@", [[db databasePath] lastPathComponent]];
  208. }
  209. - (NSString *)shortName
  210. {
  211. FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'name'"];
  212. if ([db hadError])
  213. return @"Unknown MBTiles";
  214. [results next];
  215. NSString *shortName = [results stringForColumnIndex:0];
  216. [results close];
  217. return shortName;
  218. }
  219. - (NSString *)longDescription
  220. {
  221. FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'description'"];
  222. if ([db hadError])
  223. return @"Unknown MBTiles description";
  224. [results next];
  225. NSString *description = [results stringForColumnIndex:0];
  226. [results close];
  227. return [NSString stringWithFormat:@"%@%@%@", [self shortName], ([[self shortName] length] && [description length] ? @" - " : @""), description];
  228. }
  229. - (NSString *)shortAttribution
  230. {
  231. FMResultSet *results = [db executeQuery:@"select value from metadata where name = 'attribution'"];
  232. if ([db hadError])
  233. return @"Unknown MBTiles attribution";
  234. [results next];
  235. NSString *attribution = [results stringForColumnIndex:0];
  236. [results close];
  237. return attribution;
  238. }
  239. - (NSString *)longAttribution
  240. {
  241. return [NSString stringWithFormat:@"%@%@%@", [self shortName], ([[self shortName] length] && [[self shortAttribution] length] ? @" - " : @""), [self shortAttribution]];
  242. }
  243. - (void)removeAllCachedImages
  244. {
  245. NSLog(@"*** removeAllCachedImages in %@", [self class]);
  246. }
  247. @end