iPhone Dev Note #21: Route-Me Offline Mapping from Database
Part I: Download the osm (openstreetmap) tiles
1. Download the tiles from osm using downloadosmtiles.pl
- Download Geo-OSM-Tiles-0.02.tar.gz from CPAN
- See README file. Compile and build
perl Makefile.PL make make test make install
- Copy downloadosmtiles.pl to /usr/bin
- Usage:
downloadosmtiles.pl --lat=min_lat:max_lat --lon=min_long:max_long --zoom=min_zoom:max_zoom
How do you set the min_lat, max_lat and min_long, max_long?
- Go to www.openstreetmap.org
- Click on the “Edit” tab
- You will see the extent or bounds of the map under the section “Area to Export”
- Alternatively, you can click on “Manually select a different area” to specifically choose an area.

downloadosmtiles.pl --lat=6.9443:7.2261 --lon=125.5082:125.7104 --zoom=6:12
The tiles will be downloaded to the current directory.

Part II:Put the tiles in the sqlite database
1. Read Frank’s email to route-me group regarding map2sqlite
2. Download map2sqlite-1.0.tar.bz2.
3. Build the map2sqlite XCodeProj. Afterwards, find map2sqlite and drop it in /usr/bin.
cp map2sqlite /usr/bin
4. Run map2sqlite to import the tiles in sqlite.
map2sqlite -db ph-1.0.0.db -mapdir ph-osm-map/ 2010-08-12 17:24:40.749 map2sqlite[14113:903] map2sqlite 1.0 2010-08-12 17:24:40.756 map2sqlite[14113:903] Creating ph-1.0.0.db 2010-08-12 17:24:40.761 map2sqlite[14113:903] Importing map tiles at ph-osm-map/ 2010-08-12 17:25:03.169 map2sqlite[14113:903] 2010-08-12 17:25:03.170 map2sqlite[14113:903] Map statistics 2010-08-12 17:25:03.170 map2sqlite[14113:903] -------------- 2010-08-12 17:25:03.171 map2sqlite[14113:903] map db: ph-1.0.0.db 2010-08-12 17:25:03.171 map2sqlite[14113:903] file size: 13758464 bytes 2010-08-12 17:25:03.172 map2sqlite[14113:903] tile directory: ph-osm-map/ 2010-08-12 17:25:03.172 map2sqlite[14113:903] number of tiles: 9091 2010-08-12 17:25:03.173 map2sqlite[14113:903] zoom levels: 6 - 11 2010-08-12 17:25:03.218 map2sqlite[14113:903] zoom level 6: 12 tiles, ( 28, 52)x( 31, 54), {x=112.500000,y=21.943047}x{x=129.375000,y=0.000000} 2010-08-12 17:25:03.219 map2sqlite[14113:903] zoom level 7: 35 tiles, ( 56, 105)x( 62, 109), {x=115.312500,y=21.943047}x{x=129.375000,y=2.811371} 2010-08-12 17:25:03.222 map2sqlite[14113:903] zoom level 8: 117 tiles, ( 112, 210)x( 124, 218), {x=115.312500,y=21.943047}x{x=127.968750,y=4.214943} 2010-08-12 17:25:03.223 map2sqlite[14113:903] zoom level 9: 450 tiles, ( 225, 420)x( 249, 437), {x=115.312500,y=21.289375}x{x=127.968750,y=4.214943} 2010-08-12 17:25:03.225 map2sqlite[14113:903] zoom level 10: 1715 tiles, ( 450, 841)x( 498, 875), {x=115.664062,y=21.289375}x{x=127.968750,y=4.565474} 2010-08-12 17:25:03.231 map2sqlite[14113:903] zoom level 11: 6762 tiles, ( 900, 1683)x( 997, 1751), {x=115.839844,y=21.289375}x{x=127.968750,y=4.565474}
5. ph-osm-map is 43.9 MB but was compressed to ph-1.0.0.db (13.8 MB)
Part III: Downlaod the route-me code from trunk and run some examples.
- Follow this previous tutorial
Part IV: Patch the trunk to incorporate the RMDBMapSource from Frank Schroder
1. What we need to add to the trunk. Download RMDBMapSource.zip
+ RMDBMapSource.h + RMDBMapSource.m + RMDBTileImage.h + RMDBTileImage.m
Copy the files above to the “Map” directory.

2. Edit RMTileImage.h and RMTileImage.m base on the patch below.
Index: MapView/Map/RMTileImage.h =================================================================== --- MapView/Map/RMTileImage.h (revision 605) +++ MapView/Map/RMTileImage.h (working copy) @@ -37,8 +37,10 @@ #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 @@ + (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; Index: MapView/Map/RMTileImage.m =================================================================== --- MapView/Map/RMTileImage.m (revision 605) +++ MapView/Map/RMTileImage.m (working copy) @@ -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> @@ -108,6 +109,11 @@ return [image autorelease]; } ++ (RMTileImage*)imageForTile:(RMTile) _tile fromDB: (FMDatabase*)db +{ + return [[[RMDBTileImage alloc] initWithTile: _tile fromDB:db] autorelease]; +} + -(void) cancelLoading { [[NSNotificationCenter defaultCenter] postNotificationName:RMMapImageLoadingCancelledNotification
We just need to add these lines on RMTileImage.h:
+#import "FMDatabase.h" ... ++ (RMTileImage*)imageForTile: (RMTile) tile fromDB: (FMDatabase*)db;
do the same for RMTileImage.m:
+#import "RMDBTileImage.h" ... ++ (RMTileImage*)imageForTile:(RMTile) _tile fromDB: (FMDatabase*)db +{ + return [[[RMDBTileImage alloc] initWithTile: _tile fromDB:db] autorelease]; +}
UPDATE (OCT 15, 2010): I am attaching my current RMTileImage.h and RMTileImage.m so you guys could double-check the changes I made. RMTileImage.zip
4. Still with me? Comment NSAssert on 609 on RMMapContents.m

Part V: RouteMeSampleMapDBOffline code
1. Download RouteMeSampleMapDBOffline.zip
2. Drop the project in the samples directory.

3. Build. You should be able to build this since the header path is relative to the route-me trunk.

4. Run from the simulator

Hi, thank you for this article which helps me a lot to read offline map from database. I have integrated the code into my project and it loads the db well. But I am not able to export the tiles from OpenStreetMap, the first link seems invalid currently.
Could you please describe how to use downloadosmtiles.pl?
Hey,
I updated the tutorial explaining downloadosmtiles.pl. You can get it from CPAN, compile and build. Afterwards, you can grab the bounds of your map from osm.
Cheers,
rupert
Hello, Thank you for your article but i have a few questions:
- you say (Part III: Download the route-me code from trunk and run some examples.)
ok i did and it is revision 633
- you say (2. Edit RMTileImage.h and RMTileImage.m base on the patch below.)
which exactly patch file is it?
(http://groups.google.com/group/route-me-map/files)
thanks in advance!
This is great – thanks so much!
I have a static set of map tile loaded in and it all works wonderfully.
I would love to find a way to have the map view not overshoot the edges of my included tiles and go off into “grey background no-man’s land”.
Is there a way to either:
– add to the image loading method and respond to a nil image
or better
– have map view stop scrolling a specific lat/lng boundaries
thanks again for your help.
Greg
Hello,
Thank you for this nice tutorial. I followed all the Steps, but now i get an Exception,wich i will post at the End of this Comment, and don`t know how to fix it. I tried with route-me Version 0.5 and 0.4. The normal Version of Route
-me with your previous Tutorial is running without any Problems. After patching the Files for loading the tiles from my own Database i get the Exception with my own Project and with your RouteMeSampleMapOffline Example as well. A Difference between your tutorial and my Worksteps ist that in the RMMapContents.m there is no NSAssert on Line 608. There is no NSAssert like this in the whole File. Is it possible that you have used an older Version than 0.4 of route-me for your tutorial?
It would be nice if you could contact me.
Greets Marcus
Exception:
2010-09-27 13:36:07.809 RouteMeSampleMapDBOffline[15914:207] Failed to create writable database file with message ‘The operation couldn’t be completed. No such file or directory’.
2010-09-27 13:36:07.814 RouteMeSampleMapDBOffline[15914:207] initWithFrame: logged method call: -[MapView at 0,0--2,0 initWithFrame:] (line 77)
2010-09-27 13:36:07.815 RouteMeSampleMapDBOffline[15914:207] performInitialSetup logged method call: -[MapView at 0,0-320,460 performInitialSetup] (line 58)
2010-09-27 13:36:07.817 RouteMeSampleMapDBOffline[15914:207] Opening db map source ph-1.0.0.db
2010-09-27 13:36:07.818 RouteMeSampleMapDBOffline[15914:207] Tile size: -2147483648 pixel
2010-09-27 13:36:07.819 RouteMeSampleMapDBOffline[15914:207] Supported zoom range: 0 – -1042284544
2010-09-27 13:36:07.820 RouteMeSampleMapDBOffline[15914:207] Coverage area: (-2147483648.000000,-2147483648.000000) x (-2147483648.000000,-2147483648.000000)
2010-09-27 13:36:07.821 RouteMeSampleMapDBOffline[15914:207] Center: (-2147483648.000000,-2147483648.000000)
2010-09-27 13:36:07.823 RouteMeSampleMapDBOffline[15914:207] -[RMFractalTileProjection initFromProjection:tileSideLength:maxZoom:minZoom:]: unrecognized selector sent to instance 0x5d2e0b0
2010-09-27 13:36:07.826 RouteMeSampleMapDBOffline[15914:207] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[RMFractalTileProjection initFromProjection:tileSideLength:maxZoom:minZoom:]: unrecognized selector sent to instance 0x5d2e0b0′
*** Call stack at first throw:
(
0 CoreFoundation 0x026eb919 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x025005de objc_exception_throw + 47
2 CoreFoundation 0x026ed42b -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x0265d116 ___forwarding___ + 966
4 CoreFoundation 0x0265ccd2 _CF_forwarding_prep_0 + 50
5 RouteMeSampleMapDBOffline 0x00019eda -[RMDBMapSource initWithPath:] + 1253
6 RouteMeSampleMapDBOffline 0x00002bb6 -[RouteMeSampleMapDBOfflineViewController viewWillAppear:] + 368
7 UIKit 0x0037198a -[UIView(Hierarchy) _willMoveToWindow:withAncestorView:] + 207
8 UIKit 0×00373742 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 326
9 UIKit 0x00371d87 -[UIView(Hierarchy) addSubview:] + 57
10 RouteMeSampleMapDBOffline 0x0000268e -[RouteMeSampleMapDBOfflineAppDelegate applicationDidFinishLaunching:] + 123
11 UIKit 0x0034459c -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1252
12 UIKit 0x003469a1 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 346
13 UIKit 0×00350452 -[UIApplication handleEvent:withNewEvent:] + 1958
14 UIKit 0×00349074 -[UIApplication sendEvent:] + 71
15 UIKit 0x0034dac4 _UIApplicationHandleEvent + 7495
16 GraphicsServices 0x02dd7afa PurpleEventCallback + 1578
17 CoreFoundation 0x026ccdc4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
18 CoreFoundation 0x0262d737 __CFRunLoopDoSource1 + 215
19 CoreFoundation 0x0262a9c3 __CFRunLoopRun + 979
20 CoreFoundation 0x0262a280 CFRunLoopRunSpecific + 208
21 CoreFoundation 0x0262a1a1 CFRunLoopRunInMode + 97
22 UIKit 0×00346226 -[UIApplication _run] + 625
23 UIKit 0x00351b58 UIApplicationMain + 1160
24 RouteMeSampleMapDBOffline 0x000025f0 main + 102
25 RouteMeSampleMapDBOffline 0×00002581 start + 53
)
terminate called after throwing an instance of ‘NSException’
Program received signal: “SIGABRT”.
I solved the Problem by using the latest Revision from the SVN Repository instead of using the 0.5 Release from Google Code Page.
@Bourzanis:
Don’t use the patch found in the google group files section (route-me-trunk-db-tilesource-rev605-2009-12-23.patch
) because it refers to rev605 which obviously is not trunk.
I recommend you download the trunk, then follow the code above on how to edit RMTileImage.h and RMTIleImage.m.
@greg:
– have map view stop scrolling a specific lat/lng boundaries
If we can set the maxZoom and minZoom, then I assume this is possible from RMContents. Hang on..
Quick search from RouteMe Google Group yields:
I suggest you study Anna’s code attached on this post: http://groups.google.com/group/route-me-map/browse_thread/thread/4f07179530ae3f94#
Let me know if it works for you…
@marcus
Glad you figured it out :)
For others, the way this tutorial works is by using route-me-trunk and the edited files. (im not using the word “patch” anymore as not to confuse it with the patch files found in the google group file section).
Thus, by using trunk, we get the latest route-me code + offfline support..
It would appear that RMDBTileImage leaks a NSMutableData object on map move and scroll. It looks like the NSMutableData object used for creating the image is retained when setting the layer.contents property in UpdateImageUsingImage, although it is not clear how to reduce the retain count on the NSMutableData object at this point.
I’ve checked to make sure that all of the objects being allocated are getting released and can’t find any obvious issues – looks like a very pesky bug!
Here’s the stack trace on the object that’s getting leaked:
9 -[RMMapContents initWithView:tilesource:centerLatLon:zoomLevel:maxZoomLevel:minZoomLevel:backgroundImage:] MapView/Map/RMTileLoader.m:211
8 -[RMTileImageSet addTiles:ToDisplayIn:] MapView/Map/RMTileImageSet.m:365
7 -[RMTileImageSet addTile:At:] MapView/Map/RMTileImageSet.m:263
6 -[RMCachedTileSource tileImage:] /MapView/Map/RMCachedTileSource.m:75
5 -[RMDBMapSource tileImage:] /MapView/Map/RMDBMapSource.m:222
4 +[RMTileImage imageForTile:fromDB:] Map/RMTileImage.m:168
3 -[RMDBTileImage initWithTile:fromDB:] Map/RMDBTileImage.m:106
2 -[FMResultSet dataForColumnIndex:] /Users/tobin1/Documents/Sutro Project/iPhone Guides/mobilelocal-offlinemaps/Classes/../Classes/FMResultSet.m:244
1 Foundation +[NSMutableData(NSMutableData) dataWithLength:]
0 Foundation -[NSConcreteMutableData initWithLength:]
“Move and zoom” that is… (basically any action that initiates loading a new tile)
the new route-me at Git-hub is patched with the update.
Finally, someone took the initiative of forking this to github https://github.com/route-me/route-me
Hello rupert,
i am new in offline db mode of maps. please tell me when i go to downloadosmtiles.pl link, to download open street map tiles there are 4 format available to export. i m confused which format i will download for my demo project ?
Thanks in advance.
Hey rupert,
I would really appreciate some help with my app.
I followed your tutorial and the app I built runs fine in the simulator running iOS 4.2.
But when I built it for a device, an actual iphone. The mapView doesn’t load at all.
It seems to me that it is a problem with the loading of my .db file…?
In the simulator I get:
2011-02-01 13:26:29.368 app[33801:207] Opening db map source KensingtonMap.db
2011-02-01 13:26:29.371 app[33801:207] Tile size: 256 pixel
2011-02-01 13:26:29.372 app[33801:207] Supported zoom range: 0 – 1076756480
2011-02-01 13:26:29.372 app[33801:207] Coverage area: (-33.912594,151.222687) x (-33.922852,-33.922852)
2011-02-01 13:26:29.373 app[33801:207] Center: (-33.917725,151.230927)
2011-02-01 13:26:29.374 app[33801:207] logged method call: -[ initWithView:tilesource:] (line 97)
2011-02-01 13:26:29.375 app[33801:207] logged method call: -[ initWithView:tilesource:centerLatLon:zoomLevel:maxZoomLevel:minZoomLevel:backgroundImage:] (line 119)
2011-02-01 13:26:29.376 app[33801:207] initializing memory cache with capacity 32
But when running on my iPhone, I get:
2011-02-01 13:28:06.715 app[4204:307] Opening db map source KensingtonMap.db
2011-02-01 13:28:06.721 app[4204:307] Tile size: -2147483648 pixel
2011-02-01 13:28:06.727 app[4204:307] Supported zoom range: 0 – -1042284544
2011-02-01 13:28:06.733 app[4204:307] Coverage area: (-2147483648.000000,-2147483648.000000) x (-2147483648.000000,-2147483648.000000)
2011-02-01 13:28:06.739 app[4204:307] Center: (-2147483648.000000,-2147483648.000000)
2011-02-01 13:28:06.758 app[4204:307] logged method call: -[ initWithView:tilesource:] (line 97)
2011-02-01 13:28:06.764 app[4204:307] logged method call: -[ initWithView:tilesource:centerLatLon:zoomLevel:maxZoomLevel:minZoomLevel:backgroundImage:] (line 119)
2011-02-01 13:28:06.774 app[4204:307] initializing memory cache with capacity 32
It seems like its not allocating the .db file correctly, I can’t fix it for the life of me. Any help would be GREATLY appreciated.
@sandeep_iphone: The downloadosmtiles.pl is a perl script which you run from the terminal. Obviously, you need Perl to run the script. Once it runs, it creates the directory structure and download the tiles automatically ( i think in png–don’t hold me onto this). There is no option export format that I am aware of in the perl script. It only needs the extent/bounds and zoom.
If you are referring to the “Format to Export” option found in Openstreetmap.org (edit tab), don’t use those. I only used that page to know/control the map bounds that I want to export. I explicitly specify the map bounds to the perl script (downloadosmtiles.pl)
@cellininicholas:
>It seems to me that it is a problem with the loading of my .db file…?
Just to be sure.. start fresh..
1. From the device, remove the app, thus removing its documents, db, etc.
2. Build and Debug on device. It should copy the db (i.e KensingtonMap.db) to the ../Documents/..
(See createCopyOfDatabaseIfNeeded in AppDelegate.m–I am recalling from top of my head, may not be exact method name.)
Note: Do this if you have changes in the tile db, I don’t think it gets overwritten everytime you “build and debug”. Need to check. Not sure.
3. If you get a gray background, then MapView loaded, its just that the center is somewhere..
This may be hard to troubleshoot, I need to see code and map.db. I know this coordinate (-33.912594,151.222687) is somewhere in AU, so drop me an email at rupert@2rmobile.com so I can reply offlist for contact etc.
cheers,
rupert
Perfectly… you did a great job!!!
Could you help me with the following error:
Undefined symbols:
“_OBJC_CLASS_$_RMDBMapSource”, referenced from:
objc-class-ref-to-RMDBMapSource in RouteMeSampleMapDBOfflineViewController.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
All Settings in Header Search Paths are set correctly…
I don’t know, how to get rid of this last 1 error…
Thanks…
Hello Rupert,
I have tried to run perl, but as you know i m not good in perl so nothing is done. for you i did this in my mac terminal window.
Last login: Mon Feb 14 15:59:58 on ttys000
Sandeep-Singhs-Mac-mini:~ Sandeep$ perl
/user/bin/perl
Bareword found where operator expected at – line 1, near “/user/bin”
(Missing operator before bin?)
cd ~/desktop
perl downloadosmtiles.pl –lat=6.9443:7.2261 –lon=125.5082:125.7104 –zoom=6:12
perl Makefile.PL
make
make test
make install
But nothing happen on my desktop. Please help me because i don’t know a single word in Perl.
Thanks in Advance….
while using downloadosmtiles.pl, it gives me the following error –
bash: /usr/bin/downloadosmtiles.pl: Permission denied
Could anyone please help me to solve the issue?
I need help to load my own .db file, I can’t figure out how to do that and how to center the map. Any help?
Hi Rupert
I am also getting this error
Undefined symbols:
“_OBJC_CLASS_$_RMDBMapSource”, referenced from:
objc-class-ref-to-RMDBMapSource in RouteMeSampleMapDBOfflineViewController.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
please help me to resolve it