«

»

dic 13 2012

MapsForge: OpenStreetMap en Android 3/3

 

 

Y vamos llegando al final, después de enseñaros como integrar MapsForge en nuestras apps y como aprovechar su API para overlays, hoy os contaremos como integrar los mapas offline en nuestra apps y así poder prescindir de la conexión de datos.

 

Lo primero que deberemos hacer es obtener nuestro archivo de mapas que insertaremos en nuestra app, estos mapas irán en un formato especial .map que obtendremos gracias a Osmosis que nos ayudará a convertir los mapas de OpenStreetMap en formato .osm al nombrado anteriormente. Como comentamos en un post anterior la virtud de estos mapas es que son vectoriales y serán renderizados gracias a MapsForge.

 

Para poder ejecutar Osmosis lo descargaremos de la url que indicamos a continuación, posteriormente lo descomprimimos en un directorio de nuestra elección y configuramos el path de sistema para que detecte el directorio bin de Osmosis.

 

http://bretth.dev.openstreetmap.org/osmosis-build/osmosis-latest.tgz

 

Una vez realizado el proceso de instalación teclearemos ‘osmosis’ desde la consola y comprobamos que todo funciona correctamente. Nos debería salir instrucciones del programa.

 

NOTA: La implementación de Osmosis esta basada en Maven y he detectado que si tenemos Maven instalado se generan conflictos haciendo imposible la ejecución correcta del mismo. En mi caso lo solucione creando una maquina virtual y ejecutándolo allí en un sistema limpio. Osmosis es una aplicación java y por tanto lo podréis ejecutar tanto en Windows como Linux.


Osmosis también nos permite descargar los mapas de OpenStreeMap, para ello deberemos usar el siguiente comando:

 

osmosis --ra left=--6.0497 bottom=36.9059 right=--6.0998 top=36.9326 --write-xml lebrija.osm

 

Nota: La descarga de datos desde OpenStreetMap está limitada 0.25 grados o 50000 nodos, por lo tanto en la mayoría de los casos este sistema se nos quedará corto.

 

Si nuestras necesidades exceden las limitaciones de descarga de OpenStreetMap podemos acceder a portales que suministran archivos más extensos, incluso del planeta completo. Un ejemplo de portal sería geofabrik:

 

http://download.geofabrik.de/openstreetmap/

 

Una vez tenemos el archivo de mapa necesario y nuevamente gracias a Osmosis podemos recortarlo para limitarlo a la zona requerida:

 

osmosis --read-xml spain.osm --bb left=-6.0497 bottom=36.9059  right=-6.0998 top=36.9326 --write-xml lebrija.osm

 

Llegados a este punto tendríamos nuestro fichero .osm necesario y solo nos quedaría convertirlo al formato necesario para la lectura por parte de MapsForge. Para ello nos descargaremos desde el portal de MapsForge un plugin que añadiremos a Osmosis y que nos ayudara en este menester. A continuación el enlace:

 

mapsforge-map-writer-0.3.0-jar-with-dependencies.jar

 

Este fichero jar lo copiaremos dentro del directorio ‘lib/default’ de Osmosis y a continuación dentro del directorio ‘osmosis/config’ crearemos el fichero osmosis-plugins.conf al que deberemos añadir la siguiente linea:

 

org.mapsforge.map.writer.osmosis.MapFileWriterPluginLoader

 

Pues bien, ya lo tenemos todo listo para convertir nuestros mapas, a continuación os indico el comando necesario:

 

osmosis --read-xml lebrija.osm --mapfile-writer file=lebrija.map bbox=minLat,minLon,maxLat,maxLon

 

Para poder usar los mapas descargados deberemos incluir los mismos en la tarjeta SD en un directorio de nuestra elección, para conseguirlo los copiaremos en el directorio ‘assets’ de nuestro proyecto y los copiaremos a la SD gracias al siguiente código:

 

AssetManager am = getAssets();

try {

    File dir = new File(Environment.getExternalStorageDirectory() + "/playandtourosm/");

    if (!dir.exists()) {
        dir.mkdir();
    }

    String fileName = DESTINATION_FILENAME;
    File destinationFile = new File(Environment.getExternalStorageDirectory() + "/playandtourosm/" + fileName);

    if (!destinationFile.exists()) {
        InputStream in = am.open(ORIGIN_FILENAME);
        FileOutputStream f = new FileOutputStream(destinationFile);
        byte[] buffer = new byte[1024];

        int len1 = 0;

        while ((len1 = in.read(buffer)) > 0) {
            f.write(buffer, 0, len1);
        }

        f.close();
    }

} catch (Exception e) {
    Log.e("CopyFileFromAssetsToSD", e.getMessage());
}

 

NOTA: Android al compilar nuestra app comprime alguno formatos de archivos alojados en assets, entre los que se incluye los ficheros .map, para evitar esto bastará que cuando copiemos nuestro fichero de mapas en assets lo hagamos con la extensión cambiada (por ejemplo .mp3) y al realizar la copia a la tarjeta SD le volvamos a cambiar la extensión (DESTINATION_FILENAME).

 

Con esto y el código de activity que os mostramos a continuación ya lo tendríamos todo listo para mostrar nuestros mapas offline:

 

public class MyOsmActivity extends MapActivity {   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MapView mapView = new MapView(this);
        mapView.setClickable(true);
        mapView.setBuiltInZoomControls(true);

        String filepath = Environment.getExternalStorageDirectory().getPath() + "/maps/ramblas.map";
        mapView.setMapFile(new File(filepath));
        setContentView(mapView);        
    }
}

 

Como último apunte señalar que otro de los puntos flacos de la librería es que carece de la posibilidad de limitar el desplazamiento por el mapa a la zona descargada, pero he estado trabajando en ello y en el siguiente link que os proporciono podréis encontrar unas modificaciones de la librería para incluir esta funcionalidad. Esta un poco verde aun y es mejorable pero ya es usable.

 

http://code.google.com/p/mapsforge/issues/detail?id=205

 

Ya hemos finalizo, espero que os sea de utilidad, nosotros ya lo estamos usando en nuestras apps.

 

Fuente | Ingens Blog

 

Acerca del autor

JMPergar

Mobile Developer at @BeRepublic & Founder of @AndroCode. Silver Speaker & Member of Core Team at @GDGBarcelona.

  • Julian

    Hola, por mas que intento hacer que funcione osmosis me ha sido imposible despues de dos dias liado con ello. Me da el que pongo debajo del mensaje.

    Por otra parte tengo el mapa entero de España en formato .map pero necesito recortarlos en trozos pequeños que abaque solo una ciudad. ¿No conoce algun programa que recorte archivos .map aparte de osmosis?

    Un saludo

    Exception in thread “main” java.lang.NoClassDefFoundError: org/codehaus/classwor
    lds/Launcher
    Caused by: java.lang.ClassNotFoundException: org.codehaus.classworlds.Launcher
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    Could not find the main class: org.codehaus.classworlds.Launcher. Program will
    exit.

    • http://www.linkedin.com/in/jmpergar JMPergar

      ¿Tienes Maven instalado en la misma maquina?, a mi me dio conflicto entre los dos y lo tuve que instalar en una maquina virtual limpia.

  • Julian

    No tengo maven instalado, en tu tutorial lo describes y fue lo primero que mire, pero nada.

    Te explico como lo he instalado por si se te ocurre el porque de mi error.

    En este directorio he descomprimido el zip de osmosis.
    C:\Users\Julian\Application Data\Openstreetmap\

    Ahora todas las carpetas de osmosis estan en este directorio
    C:\Users\Julian\Application Data\Openstreetmap\osmosis

    Aqui he creado una carpeta llamada “Plugins” y he metido este jar
    “mapsforge-map-writer-0.3.0-jar-with-dependencies.jar”

    En la carpeta config he metido un archivo que he creado llamado.
    “osmosis-plugins.conf” de contenido le he metido la siguiente linea “org.mapsforge.map.writer.osmosis.MapFileWriterPluginLoader”

    Despues, en configuracion avanzada del sistema en variables de entorno he escrito esta variable en path.
    C:\Users\Julian\Application Data\Openstreetmap\osmosis\bin

    Luego doy doble click a osmosis.bat ejecutando como administrador y sale el error que he escrito en mi primer post. No obstante para probar meto el comando
    que has puesto en el hilo para probar y vuelve a salir el error.

    ¿ves algo mal en mi instalación?

    Gracias por tu tiempo y sobretodo por tus turiales que me han sacado de muchos apuros.

  • Enrique

    Hola, Cuando voy a convertir un mapa de osm a map en que directorio debo colocar el archivo osm para que osmosis lo reconozca de la forma en que explicas el tutorial???

    • Jorge Fuentes

      El archivo osm se copia en la carpeta osmosis\bin , ahi mismo quedará el nuevo archivo .map
      Saludos

  • Juaan Marco

    Y Si quisiera crear rutas entre dos puntos ? que alternativas hay ??

  • Mario

    Hola, antes que nada buenos tutoriales desde los de osmdroid hasta estos de mapsforge, sin embargo al lelvar a cabo este tutorial para ver un mapa offline tengo problemas ya que cuando intento ver el mapa desde mi archivi *.map la app cuando se abre se ve blanco totalmente y segundos despues se cierra. Los mensajes enviados por logCat son los soguientes:

    03-27 21:44:23.582: E/AndroidRuntime(24921): FATAL EXCEPTION: MapWorker
    03-27 21:44:23.582: E/AndroidRuntime(24921): java.lang.NullPointerException
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.android.maps.mapgenerator.databaserenderer.DatabaseRenderer.renderArea(DatabaseRenderer.java:229)
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.android.maps.rendertheme.renderinstruction.Area.renderWay(Area.java:128)
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.android.maps.rendertheme.Rule.matchWay(Rule.java:217)
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.android.maps.rendertheme.Rule.matchWay(Rule.java:221)
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.android.maps.rendertheme.RenderTheme.matchWay(RenderTheme.java:198)
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.android.maps.rendertheme.RenderTheme.matchClosedWay(RenderTheme.java:126)
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.android.maps.mapgenerator.databaserenderer.DatabaseRenderer.renderWaterBackground(DatabaseRenderer.java:275)
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.map.reader.MapDatabase.processBlocks(MapDatabase.java:562)
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.map.reader.MapDatabase.executeQuery(MapDatabase.java:259)
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.android.maps.mapgenerator.databaserenderer.DatabaseRenderer.executeJob(DatabaseRenderer.java:169)
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.android.maps.mapgenerator.MapWorker.doWork(MapWorker.java:73)
    03-27 21:44:23.582: E/AndroidRuntime(24921): at org.mapsforge.android.maps.PausableThread.run(PausableThread.java:94)

    No se si hice algo mal; el archivo map lo conseguí con osmosis.

    De antemano gracias y espero puedas ayudarme

    • Jorge Fuentes

      Tengo el mismo problema, de hecho parece que acabas de pegar los errores de mi logcat. lo curioso es que con otro archivo que generé de la misma forma si funciona, así que debe ser algo con el mapa.

    • Jorge Fuentes

      Problema resuelto, revisa el bbox, al menos yo lo estaba dejando muy grande. Lo ajusté bien y problema resuelto. Ahora necesito juntar dos archivos osm, en uno tengo las carreteras y poi pero no tengo la línea de costa que si aparece en el otro.
      Si alguien tiene algún tip.

  • http://codementia.blogspot.com.es/ Eduard

    Interesante y muy util artículo aunque, por desgracia, sin utilidad. Me he pasado unos días viendo que alternativas hay a la API de Google Maps y ni una sola funciona como se espera. Ya de la documentación ni hablamos. Suerte a los que lo intenten.

  • Luguer

    Hola, estoy utilizando mapsforge en un proyecto y necesito una funcion que me devuelva si un punto esta dentro de un poligono. Mapsforge trae esta funcion ???

  • http://gravatar.com/domocodigo Wilfo

    Luguer lo que dices se puede resolver con un algoritmo, la herramienta que menciona es solo para visualizar y cargar puntos para que sirva de referencia pero en ningún momento te va a decir si algo esta o no dentro d eun punto determinado.Puedes resolverlo trazando un kml linestring y luego mirad tu gps para ver donde estás.Así lo resolví yo.