Generating OsmAnd Map Files
When I pass by an area that does not get much love on Openstreetmap, I end up
fixing some things myself. If I stay there for a while though, my offline maps
on OsmAnd become outdated. OsmAnd maps only get an update once a month, so my
map fixes often will not be visible till after I have left the area. After a
few days of improving the map though, it would be handy if what I have done so
far is actually visible in my offline map. Then I can further improve on that
instead of on outdated information. To get around this limitation, I had a look
at how to generate the OsmAnd map files (.obf
) myself.
Seems to be simple enough. Go to
Geofabrik to download the area of
your choice. In my particular case: Pennsylvania, USA. Download the .osm.pbf
file. Next go to the OsmAnd website and download
OsmAndMapCreator, currently on the right side
column of that downloads page. It is a Java .jar
file with its libraries and
some wrapper scripts to run the .jar
file.
Open OsmAndMapCreator with the provided bash script OsmAndMapCreator.sh
. A
window will appear. Open the menu “File → Create .obf from osm file…”.
Select the .osm.pbf
file you downloaded before and it will start processing
it. So far so good!
… and then it crashed on me at 67% processed.
java.lang.OutOfMemoryError: Java heap space
at gnu.trove.map.hash.TLongObjectHashMap.rehash(TLongObjectHashMap.java:168)
at gnu.trove.impl.hash.THash.postInsertHook(THash.java:387)
at gnu.trove.map.hash.TLongObjectHashMap.doPut(TLongObjectHashMap.java:269)
at gnu.trove.map.hash.TLongObjectHashMap.put(TLongObjectHashMap.java:240)
at net.osmand.obf.preparation.OsmDbCreator.getConvertId(OsmDbCreator.java:222)
at net.osmand.obf.preparation.OsmDbCreator.convertId(OsmDbCreator.java:122)
at net.osmand.obf.preparation.OsmDbCreator.acceptEntityToLoad(OsmDbCreator.java:368)
at net.osmand.osm.io.OsmBaseStorage.acceptEntityToLoad(OsmBaseStorage.java:313)
at net.osmand.osm.io.OsmBaseStoragePbf$1.registerEntity(OsmBaseStoragePbf.java:43)
at net.osmand.osm.io.OsmBaseStoragePbf$1.parseWays(OsmBaseStoragePbf.java:195)
at crosby.binary.BinaryParser.parse(BinaryParser.java:104)
at crosby.binary.BinaryParser.handleBlock(BinaryParser.java:51)
at crosby.binary.file.FileBlock.process(FileBlock.java:120)
at crosby.binary.file.BlockInputStream.process(BlockInputStream.java:15)
at net.osmand.osm.io.OsmBaseStoragePbf.parseOSMPbf(OsmBaseStoragePbf.java:214)
at net.osmand.obf.preparation.IndexCreator.extractOsmToNodesDB(IndexCreator.java:297)
at net.osmand.obf.preparation.IndexCreator.initDbAccessor(IndexCreator.java:385)
at net.osmand.obf.preparation.IndexCreator.generateIndexes(IndexCreator.java:618)
at net.osmand.obf.preparation.IndexCreator.generateIndexes(IndexCreator.java:538)
at net.osmand.swing.OsmExtractionUI$18.run(OsmExtractionUI.java:819)
at net.osmand.swing.ProgressDialog$WorkerThread.run(ProgressDialog.java:87)
I tried fiddling with the memory mentioned in the .sh
file.
JAVA_OPTS="-Xms256m -Xmx4096m"
To no avail. It keeps on crashing at 67% of Pennsylvania processed.
I added the -XX:+PrintFlagsFinal
flag to the java
call to help debug.
Adding this flag spews out all the configuration keys and their values after
starting up. I used it to check whether the heapsize (uintx MaxHeapSize
) was
correctly at 4GB. It seemed to be. I upped it to 8GB, still crashing. Then I
noticed it was not increasing in the -XX:PrintFlagsFinal
output though. The
$JAVA_OPTS
variable was correctly being set, but Java seemed to not pick up
on it. Perhaps 4GB had simply been the default. I instead edited
OsmAndMapCreator.sh
so that the flags were directly in the java
command.
Can’t ignore the flag then, surely. That indeed seemed to do the trick and
OsmAndMapCreator went through processing all of the Pennsylvania file.
For reference, the original .osm.pbf
is 207 MB, the final .obf
file is 420
MB. I don’t know what size is enough for the heap, but 4 GB was not enough.
For further reference, this is what my OsmAndMapCreator.sh
file looked like
in the end. Most important part is on the final line where I added the heap
size flags directly.
#!/bin/bash
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
if [ -z "$JAVA_OPTS" ]; then
JAVA_OPTS="-Xms256m -Xmx8192m"
fi
java -Xms256m -Xmx8192m -XX:+PrintFlagsFinal -Djava.util.logging.config.file="$DIR/logging.properties" -jar "$DIR/OsmAndMapCreator.jar"
With the .obf
file generated, it is just a matter of putting it on your
phone. Find the file in ~/osmand/
and copy it to your phone. Specifically it
needs to end up in the folder /Android/data/net.osmand.plus/files/
on your
phone. I make it override the existing file for Pennsylvania
(Us_pennsylvania_northamerica.obf
). I did not test whether that was required,
but I figured this was a sure fire way for OsmAnd to pick up on it. I had
closed OsmAnd entirely (swiping it out of the active applications), I do not
know if that is required. When I opened it up again, it correctly had my
updated map area though. Great success!
Yet to find out: will it pick up on the official OsmAnd update of the PA file still?
Later update: Maybe JAVA_OPTS
is not some special environment variable to
begin with and I should have just explicitly added it in the java
command? Oh
well.
Still later update: I probably should have checked the OSM wiki beforehand. Of course they have a page about OsmAndMapCreator already. Guess this was just a learning experience for me.