Apple presentó este lunes lo nuevo en iOS 6, nuevos MacBooks, Mountain Lion.... Pero una de las cosas que más llamó la atención es el "temido" divorcio de Apple-Google con el tema del servicio de mapas. Parece que Apple se ha asociado con Tom Tom y otras compañías para que les ofrezcan los datos necesarios para su nuevo servicio.
Aún no se sabe si estos mapas podrán ofrecernos servicios Offline, y creo que es una feature casi imprescindible actualmente. Por eso la intención de este artículo es de cómo implementar en nuestros proyectos mapas offline con OpenStreetMap.

Primero de todo, nos tendremos que descargar las tiles de la zona en cuestión y para ello utilizaremos el script downloadosmtiles.pl. Este script descarga todas las tiles del mapa de un servidor de OpenStreetMap de una región geográfica específica con un rango de niveles de zoom. Las tiles serán imágenes PNG.
¿QUÉ ES ESO DE TILES?
Literalmente en inglés significa "azulejos" pero aquí nos referimos a fragmentos del mapa. Los gráficos de mapa de bits cuadrados que aparecen en una disposición de la red para mostrar un mapa (como si una red de azulejos se tratase).
DESCARGANDO TILES
Para ello deberemos descargar, compilar e instalar GEO-OSM-Tiles 0.04. Está escrito en Perl para ello deberemos ejecutar estos comandos desde la terminal:
#Si no tenemos instalado wget podemos sustituirlo por curl -O
wget http://search.cpan.org/CPAN/authors/id/R/RO/ROTKRAUT/Geo-OSM-Tiles-0.04.tar.gz
tar -xf Geo-OSM-Tiles-0.04.tar.gz
cd Geo-OSM-Tiles-0.04
# Nos tenemos que asegurar que no da ningún tipo de errores o warning
perl Makefile.PL
make
make test
sudo make install
Si nos devuelve un error similar a este "Warning: prerequisite YAML 0 not found." es que faltan por habilitar/instalar algunas librerías Perl. Para ello, lo más fácil que podemos hacer es ejecutar este comando en la terminal y una vez hecho volver a ejecutar el paso anterior:
sudo perl -MCPAN -e 'install Bundle::CPAN'
Ahora deberemos conseguir las coordenadas de la zona que queremos descargar. Para ello nos iremos al site de http://www.openstreetmap.org/ y haremos click en el apartado "Exportar". Ahora nos aparecerá cuatro campos de coordenadas en "Area a exportar", estos son los que nos interesa pero queremos una zona en concreto así que pulsaremos "Seleccionar a mano otra área" y elegimos la que deseemos en el mapa.
+19.00.51.png)
Ahora deberemos ejecutar downloadosmtiles.pl en la terminal con las coordenadas que nos devolvió antes y el nivel de zoom (en nuestro caso 15).
downloadosmtiles.pl --lat=41.3641:41.4113 --long=2.068:2.1605 --zoom=0:15 --destdir=/mydir/Desktop/mapsOfflineBarcelona/
Nos deberá haber quedado algo similar a esto:
+19.15.22.png)
CONVERTIR TILES A SQLITE
Deberemos descargar y ejecutar map2sqlite para convertir las tiles en una base de datos sqlite, la cual la utilizaremos posteriormente con la librería route-me.
wget http://www.ingens-networks.com/blog/file.axd?file=2012%2f6%2fmap2sqlite-bin.zip
tar -xf map2sqlite-bin.zip
./map2sqlite -db /dir/mapBarcelona.sqlite -mapdir /tu/carpeta/mapsOfflineBarcelona
UTILIZAR SQLITE CON ROUTE-ME
Route-me funciona actualmente con OpenStreetMap, Microsoft VirtualEarth, CloudMade, OpenAerialMap, OpenCycleMap, SpatialCloud, TileStream7, entre otros. En este artículo vamos a utilizar un proyecto de ejemplo que ya viene con Route-me "samples/SimpleMap/SimpleMap.xcodeproj".
1 - Nos descargamos el proyecto desde https://github.com/route-me/route-me
2 - Abrimos el proyecto que hemos comentado anteriormente, elegimos el scheme "SimpleMap" y ejecutamos para ver que no tenemos errores.
3 - Añadimos el sqlite generado antes al proyecto y comprobamos que lo tenemos también añadido al "Copy Bundle Resources".
+10.14.33.png)
4 - Debemos importar RMDBMapSource.h al fichero de implementación de MapViewViewController (MapViewViewController.m)
#import "RMDBMapSource.h"
5 - Añadimos estas líneas al método viewDidLoad de MapViewViewController.m:
// Localización cercana a las oficinas de Ingens Networks
CLLocationCoordinate2D coolPlace;
coolPlace.latitude = 41.364925;
coolPlace.longitude = 2.137699;
// Utilizamos el sqlite generado anteriormente
RMDBMapSource *mapSrc = [[[RMDBMapSource alloc] initWithPath:@"mapBarcelona.sqlite"] autorelease];
[[[RMMapContents alloc] initWithView:mapView tilesource:mapSrc] autorelease];
// Bloqueamos la navegación a solo los tiles que tenemos habilitado en nuestro sqlite
[mapView setConstraintsSW:CLLocationCoordinate2DMake(mapSrc.bottomRightOfCoverage.latitude, mapSrc.topLeftOfCoverage.longitude)
NE:CLLocationCoordinate2DMake(mapSrc.topLeftOfCoverage.latitude, mapSrc.bottomRightOfCoverage.longitude)];
// Centramos el mapa a la localización indicada en coolPlace
[mapView moveToLatLong:coolPlace];
Lo arrancamos en nuestro dispositivo y nos tendría que salir algo similar a esto.

6 - Ahora vamos a añadir POI´s (puntos de interes - marcas) a nuestro mapa.
// Localización cercana a las oficinas de Ingens Networks
CLLocationCoordinate2D coolPlace;
coolPlace.latitude = 41.364925;
coolPlace.longitude = 2.137699;
// Segunda localización
CLLocationCoordinate2D coolPlace2;
coolPlace2.latitude = 41.365478;
coolPlace2.longitude = 2.137799;
// Utilizamos el sqlite generado anteriormente
RMDBMapSource *mapSrc = [[[RMDBMapSource alloc] initWithPath:@"mapBarcelona.sqlite"] autorelease];
[[[RMMapContents alloc] initWithView:mapView tilesource:mapSrc] autorelease];
RMMarkerManager *markerManager = [mapView markerManager];
[mapView setDelegate:self];
// Bloqueamos la navegación a solo los tiles que tenemos habilitado en nuestro sqlite
[mapView setConstraintsSW:CLLocationCoordinate2DMake(mapSrc.bottomRightOfCoverage.latitude, mapSrc.topLeftOfCoverage.longitude)
NE:CLLocationCoordinate2DMake(mapSrc.topLeftOfCoverage.latitude, mapSrc.bottomRightOfCoverage.longitude)];
// Centramos el mapa a la localización indicada en coolPlace
[mapView moveToLatLong:coolPlace];
// Creamos los POIs
RMMarker *marker = [[RMMarker alloc]initWithUIImage:[UIImage imageNamed:@"marker-blue.png"]
anchorPoint:CGPointMake(0.5, 1.0)];
[marker setTextForegroundColor:[UIColor blueColor]];
[marker changeLabelUsingText:@"Ingens Networks"];
[markerManager addMarker:marker AtLatLong:coolPlace];
[marker release];
RMMarker *marker2 = [[RMMarker alloc]initWithUIImage:[UIImage imageNamed:@"marker-red.png"]
anchorPoint:CGPointMake(0.5, 1.0)];
[marker2 setTextForegroundColor:[UIColor blackColor]];
[marker2 changeLabelUsingText:@"Segunda"];
[markerManager addMarker:marker2 AtLatLong:coolPlace2];
[marker2 release];

Ahora bien, si queremos pintar nuestra posición obtenida a través del GPS, es tan fácil como utilizar el framework Core Location que ya está importada al proyecto. Declaramos en el archivo MapViewViewController.h que MapViewViewController cumple con el protocolo CLLocationManagerDelegate. Así pues el fichero de cabecerá quedará así:
#import <UIKit/UIKit.h>
#import "RMMapView.h"
@interface MapViewViewController : UIViewController <RMMapViewDelegate, CLLocationManagerDelegate> {
IBOutlet RMMapView * mapView;
BOOL tap;
NSInteger tapCount;
CLLocationManager *locationManager;
}
@property (nonatomic, retain) IBOutlet RMMapView * mapView;
@end
Ya solo nos faltará implementar los métodos delegados del protocolo CLLocationManagerDelegate en el fichero de implementación (MapViewViewController.m). En este ejemplo hacemos que cuando nuestra posición GPS se modifique, coja uno de los POI que creamos anteriormente y lo ubique en nuestra posición actual.
#pragma mark -
#pragma mark CLLocationManagerDelegate methods
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"No se puede encontrar la localización: %@", error);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if (mapView) {
RMMarker *marker = [[mapView markerManager].markers objectAtIndex:1];
[mapView.markerManager moveMarker:marker AtLatLon:newLocation.coordinate];
}
}