#Create your own map with OpenStreetMap
This is some note of me playing with OpenStreetMap and creating an Android app that renders the map drawn.
##Draw a map
###Get GPS trace
If you want to draw your own map, OpenStreetMap is a good choice because it's an open project with many tools and resources available.
To draw a map, the first thing to do is to get GPS trace, there are many Android apps to do this. The one I used is OSMTracker. You can recording tracks with this app and take some note and photos along the way. After the survey, the gps data can be exported as gpx file.
###Edit the map
With the surveyed gps data, we can draw the map. The best tool I think is JOSM, in which we can import the gpx file and then download from the internet the map data surrounding the surveyed area that is already in OpenStreetMap as a starting point of our edit. The OpenStreetMap's basic data structures are Nodes, Ways and Relations, these can easily be drawn using the tools in JOSM. Usually we draw these elements alongside our GPS data as guidance. JOSM also have some presets for us to set to the elements we draw, they in fact set the tags to the data structures and make them have the corresponding visual effects when rendered.
After we finished the editing of the map, we can save the data to an .osm file, these are xml files containing map data with osm data strutures.
##Using the drawn map in an Android app ###Convert it to mapsforge format The generated osm file cannot be used directly, they first need to be rendered. The best library to use on Android I find is MapsForge. But before the OSM data can be used with mapsforge, it must be converted to mapsforege's format, .map file and the tool to do this is Mapsforge Map-Writer. It's an osmosis plugin and after installed, It's simply a matter of going to osmosis's install directory and run the command:
/osmosis --read-xml file="/[osm file path]/file.osm" --mapfile-writer file="/[out put path]/dest.map"
Osmosis may complain invalid osm file format that's because the
JOSM file format saved
by JOSM is not exactly the same as the osm file download from openstreetmap server,
it have action='modify'
and don't have timestamp and some other xml attributes.
This can be easily solved by opening the osm file in vim and substitute the attributes
with a command like the following:
:%s/action='modify' visible='true'/timestamp='2008-06-27T03:38:51Z' uid='13721' user='wangchun' visible='true' version='1' /
###Using it in android To use the map in android with mapsfore, it's best to start from mapsfore's sample project, which is in the 'mapsforge-samples-androd' folder in mapsforge's source code.
There are several 'Viewer' classes such as SimplestMapViewer and StackedLayersMapViewer
that inherits from MapViewerTemplate and implements different styles of map.
MapViewerTemplate
extends from Activity
and deals with some dirty works to setup
mapsforge. So all we have to do is extending from MapViewerTemplate and overriding
some of its method to change the configurations as we like. For example by overriding
getMapViewId() and getMapFileName() we can specify the map view id and the map data file.
One important method to override is createLayers(), in which we create 'layers' and add them
to the map view, such as TileRendererLayer
and Marker
. As its name suggests, with Marker
class we can add markers which is usually a bitmap on top of the map, one thing to remember is we
need to call setDisplayModel() before a layer is added to a map view.
Now that the map is setup, we need to set the position to be displayed at the center of
the view as the map may be larger than the view port. The initial position can be set by
overriding method initializePosition() from MapViewerTemplate. The view port location and
zoom level can be updated afterwards(such as in LocationListener) with
mapView.getModel().mapViewPosition.setCenter()
and mapView.getModel().mapViewPosition.setZoomLevel()
respectively. The markers location can be set with setLatLong() method of the marker class.
One last thing to note is mapsforge expects a map file in some directory(default is /sdcard/),
while in Android we often store data in an app's asset
folder. So in onCreate()
, we need to
open the map data file in asset and write it to a file in /sdcard
directory , if it doesn't
exists.