[gosmore] 10/20: Imported Upstream version 0.0.0.svn30327

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Sat May 7 12:24:59 UTC 2016


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository gosmore.

commit 8ebc9e79378f03e31dd68ca3abbeca1452dd564d
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sat May 7 11:54:37 2016 +0200

    Imported Upstream version 0.0.0.svn30327
---
 AndroidManifest.xml                                |   60 +
 Makefile.in                                        |   61 +-
 README                                             |   31 +-
 bboxSplit.cpp                                      |   11 +-
 bounds.osm.bz2                                     |  Bin 127660 -> 114507 bytes
 dailyUpdate.sh                                     |   66 +
 default.properties                                 |   12 +
 density.c                                          |    2 +-
 elemstyles.xml                                     |   34 +-
 gosmore.nsi                                        |    5 +
 jni/Android.mk                                     |   15 +
 jni/Application.mk                                 |    4 +
 ConvertUTF.c => jni/ConvertUTF.c                   |    0
 ConvertUTF.h => jni/ConvertUTF.h                   |    0
 ceglue.c => jni/ceglue.c                           |    0
 ceglue.h => jni/ceglue.h                           |    0
 gosmore.cpp => jni/gosmore.cpp                     | 1559 ++++++++++++--------
 libgosm.cpp => jni/libgosm.cpp                     |  274 ++--
 libgosm.h => jni/libgosm.h                         |   13 +-
 jni/openglespolygon.cpp                            |  532 +++++++
 jni/openglespolygon.h                              |   42 +
 resource.h => jni/resource.h                       |    0
 translations.c => jni/translations.c               |    0
 proguard.cfg                                       |   48 +
 res/drawable-hdpi/btn_square_overlay_normal.png    |  Bin 0 -> 929 bytes
 res/drawable-hdpi/btn_zoom_down_disabled.png       |  Bin 0 -> 2376 bytes
 .../btn_zoom_down_disabled_focused.png             |  Bin 0 -> 2697 bytes
 res/drawable-hdpi/btn_zoom_down_normal.png         |  Bin 0 -> 2104 bytes
 res/drawable-hdpi/btn_zoom_down_pressed.png        |  Bin 0 -> 4306 bytes
 res/drawable-hdpi/btn_zoom_down_selected.png       |  Bin 0 -> 4348 bytes
 res/drawable-hdpi/btn_zoom_up_disabled.png         |  Bin 0 -> 2531 bytes
 res/drawable-hdpi/btn_zoom_up_disabled_focused.png |  Bin 0 -> 2829 bytes
 res/drawable-hdpi/btn_zoom_up_normal.png           |  Bin 0 -> 2065 bytes
 res/drawable-hdpi/btn_zoom_up_pressed.png          |  Bin 0 -> 3806 bytes
 res/drawable-hdpi/btn_zoom_up_selected.png         |  Bin 0 -> 3802 bytes
 res/drawable-hdpi/ic_menu_play_clip.png            |  Bin 0 -> 2291 bytes
 res/drawable-hdpi/icon.png                         |  Bin 0 -> 3481 bytes
 res/drawable-hdpi/stat_sys_upload_anim0.png        |  Bin 0 -> 927 bytes
 res/drawable-ldpi/icon.png                         |  Bin 0 -> 1518 bytes
 res/drawable-mdpi/btn_square_overlay_normal.png    |  Bin 0 -> 1279 bytes
 res/drawable-mdpi/btn_zoom_down_disabled.png       |  Bin 0 -> 1534 bytes
 .../btn_zoom_down_disabled_focused.png             |  Bin 0 -> 1867 bytes
 res/drawable-mdpi/btn_zoom_down_normal.png         |  Bin 0 -> 1305 bytes
 res/drawable-mdpi/btn_zoom_down_pressed.png        |  Bin 0 -> 2370 bytes
 res/drawable-mdpi/btn_zoom_down_selected.png       |  Bin 0 -> 2395 bytes
 res/drawable-mdpi/btn_zoom_up_disabled.png         |  Bin 0 -> 1600 bytes
 res/drawable-mdpi/btn_zoom_up_disabled_focused.png |  Bin 0 -> 1911 bytes
 res/drawable-mdpi/btn_zoom_up_normal.png           |  Bin 0 -> 1305 bytes
 res/drawable-mdpi/btn_zoom_up_pressed.png          |  Bin 0 -> 2465 bytes
 res/drawable-mdpi/btn_zoom_up_selected.png         |  Bin 0 -> 2463 bytes
 res/drawable-mdpi/ic_menu_play_clip.png            |  Bin 0 -> 1194 bytes
 res/drawable-mdpi/icon.png                         |  Bin 0 -> 2383 bytes
 res/drawable-mdpi/stat_sys_download_anim0.png      |  Bin 0 -> 588 bytes
 res/drawable/mappaint.png                          |  Bin 0 -> 792812 bytes
 res/layout/download_progress.xml                   |   24 +
 res/layout/map_help.xml                            |  107 ++
 res/layout/map_view.xml                            |   67 +
 res/layout/old_main.xml                            |   29 +
 res/layout/search.xml                              |   29 +
 res/layout/search_result.xml                       |   30 +
 res/layout/update.xml                              |   31 +
 res/menu/map.xml                                   |   19 +
 res/values/arrays.xml                              |   38 +
 res/values/strings.xml                             |   58 +
 src/org/osmu/gosmore/Gosmore.java                  |   83 ++
 src/org/osmu/gosmore/MapActivity.java              |  726 +++++++++
 src/org/osmu/gosmore/Place.java                    |   10 +
 src/org/osmu/gosmore/Preferences.java              |   54 +
 src/org/osmu/gosmore/Recent.java                   |   31 +
 src/org/osmu/gosmore/Search.java                   |  131 ++
 src/org/osmu/gosmore/Update.java                   |  243 +++
 71 files changed, 3692 insertions(+), 787 deletions(-)

diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100755
index 0000000..a2a84c1
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="org.osmu.gosmore"
+      android:versionCode="1"
+      android:versionName="1.0">
+<!-- /ion/Program\ Files/Java/jdk1.6.0_23/bin/keytool.exe -genkey -keysize 2048 -keyalg RSA -validity 10000 -->
+
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <application android:name=".Gosmore" android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="false">
+          <activity android:name=".Menu">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TAB" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".Update"
+                  android:label="Update">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TAB" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".Search"
+                  android:label="Search">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TAB" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".Recent"
+                  android:label="Recent">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TAB" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".Preferences"
+                  android:label="Preferences">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TAB" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".MapActivity"
+                  android:label="Gosmore"
+                  android:configChanges="keyboardHidden|orientation">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="7"/>
+
+</manifest> 
\ No newline at end of file
diff --git a/Makefile.in b/Makefile.in
index 3da1e07..6626f59 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -38,40 +38,33 @@ XMLFLAGS=`pkg-config --cflags libxml-2.0 || echo -I /usr/include/libxml2` \
   `pkg-config --libs libxml-2.0 || echo -l xml2 -lm`
 ARCH=arm-mingw32ce-
 else
-# To compile with mingw, install MSYS and mingw, and then download
-# the "all-in-one bundle" from http://www.gtk.org/download-windows.html
-# and unzip it to C:\msys\1.0.
-EXTRAC=-mms-bitfields -mno-cygwin -mwindows \
+
+EXTRAC=-Ilibxml2-2.7.8/include \
   `pkg-config --cflags gtk+-2.0 || echo -D NOGTK`
-EXTRAL=`pkg-config --libs gtk+-2.0`
+
+EXTRAL=`pkg-config --libs gtk+-2.0` \
+
 EXE=.exe
-W32LIBS=-lwsock32 -lwinmm
+W32LIBS=-Llibxml2-2.7.8/.libs -lxml2 -lwsock32 -lwinmm  -lgdi32
+
 endif
 
 all: gosmore$(EXE)
 
-# The planet is too big to fit into the address space of a single process on
-# a 32 bit CPUs. So we break it up into pieces (overlapping rectangles and
-# some lowzoom extracts) and then run one process for each piece. The parent
-# task then chooses the most
-# appropriate process and forwards the expose, search or routing request to
-# it. THE CODE IS NOT FINISHED. Linux version looks promising.
-gosmore:	gosmore.cpp libgosm.cpp libgosm.h bboxes.c
-		g++ -DCHILDREN=16 ${CFLAGS} ${WARNFLAGS} ${XMLFLAGS} \
-                  gosmore.cpp libgosm.cpp -o gosmore ${EXTRA}
-
-gosmore16:	gosmore.cpp libgosm.cpp libgosm.h
-		g++ -DGOSMZ=16 ${CFLAGS} ${WARNFLAGS} ${XMLFLAGS} \
-                  gosmore.cpp libgosm.cpp -o gosmore16 ${EXTRA}
-
-$(ARCH)gosmore.exe:	gosmore.cpp libgosm.cpp gosmore.rsc resource.h \
-                    libgosm.h ceglue.h ceglue.c bboxes.c
-		${ARCH}g++ ${CFLAGS} ${EXTRAC} -c gosmore.cpp
-		${ARCH}g++ ${CFLAGS} ${EXTRAC} -c libgosm.cpp
-		${ARCH}gcc ${CFLAGS} ${EXTRAC} -c ConvertUTF.c
-		${ARCH}gcc ${CFLAGS} ${EXTRAC} -c ceglue.c
-		${ARCH}g++ -static ${CFLAGS} ${EXTRAC} -o $@ \
-		  gosmore.o libgosm.o ceglue.o ConvertUTF.o gosmore.rsc $(W32LIBS)
+gosmore:	jni/gosmore.cpp jni/libgosm.cpp jni/libgosm.h jni/bboxes.c \
+		jni/openglespolygon.h jni/openglespolygon.cpp
+		g++ ${CFLAGS} ${WARNFLAGS} \
+                  jni/gosmore.cpp jni/libgosm.cpp jni/openglespolygon.h \
+                  jni/openglespolygon.cpp -o gosmore ${EXTRA} ${XMLFLAGS}
+
+$(ARCH)gosmore.exe:	jni/gosmore.cpp jni/libgosm.cpp gosmore.rsc jni/resource.h \
+                    jni/libgosm.h jni/ceglue.h jni/ceglue.c bboxes.c
+		${ARCH}g++ ${CFLAGS} ${EXTRAC} -c jni/gosmore.cpp
+		${ARCH}g++ ${CFLAGS} ${EXTRAC} -c jni/libgosm.cpp
+		${ARCH}gcc ${CFLAGS} ${EXTRAC} -c jni/ConvertUTF.c
+		${ARCH}gcc ${CFLAGS} ${EXTRAC} -c jni/ceglue.c
+		${ARCH}g++ -static ${EXTRAL} \
+		  gosmore.o libgosm.o ceglue.o ConvertUTF.o gosmore.rsc $(W32LIBS)  -o $@
 
 tagcmp.o:	tagcmp.l
 
@@ -80,20 +73,20 @@ gosmore.rsc:	gosmore.rc icons.bmp icons-mask.bmp gosmore.ico
 
 WIKIPAGE=http://wiki.openstreetmap.org/index.php/Special:Export/Gosmore
 translations.c: extract
-		wget -O - ${WIKIPAGE}/Translations |./extract >translations.c
+		wget -O - ${WIKIPAGE}/Translations |./extract >jni/translations.c
 
 extract:	extract.c
 		${CC} ${CFLAGS} ${XMLFLAGS} extract.c -o extract
 
-bboxes.c:	density.c density.txt
-		gcc -lm density.c -o density
+jni/bboxes.c:	density.c density.txt
+		gcc density.c -lm -o density
 		./density <density.txt >density.sh
 # wget http://www.openstreetmap.org/api/0.6/changeset/1707270/download -O \
 #   countries.osm
 
-osmunda:	osmunda.cpp libgosm.cpp libgosm.h
+osmunda:	osmunda.cpp jni/libgosm.cpp jni/libgosm.h
 		g++ ${CFLAGS} ${WARNFLAGS} ${XMLFLAGS} \
-		  osmunda.cpp libgosm.cpp -o osmunda
+		  osmunda.cpp jni/libgosm.cpp -o osmunda
 voices:
 		echo '(voice_rab_diphone)' >/tmp/voice_rab_diphone
 		echo 'At the junction, turn left.' | festival_client \
@@ -178,7 +171,7 @@ routingTest: gosmore
 
 dist:
 	mkdir gosmore-$(VERSION)
-	cp gosmore.cpp Makefile elemstyles.xml icons.csv icons.xpm  README \
+	cp jni/gosmore.cpp Makefile elemstyles.xml icons.csv icons.xpm  README \
 	  gosmore-$(VERSION)
 	tar zcf gosmore-$(VERSION).tar.gz gosmore-$(VERSION)
 	rm -rf gosmore-$(VERSION)
diff --git a/README b/README
index 0293175..cf54b0d 100644
--- a/README
+++ b/README
@@ -49,6 +49,31 @@ countries.osm comes from openstreetmap.org
 
 The png files comes openclipart.org and other public domain sources.
 
-Everything else are placed by in the public domain by its authors.
-Written by Nic Roets with contribution(s) from Dave Hansen, David Dean and
-others.
+Everything else was written by Nic Roets with contributions from David Dean,
+Dave Hansen and others and is placed under the Simplified BSD License :
+
+Copyright 2010 Nic Roets. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, this list of
+      conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright notice, this list
+      of conditions and the following disclaimer in the documentation and/or other materials
+      provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY NIC ROETS ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NIC ROETS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those of the
+authors and should not be interpreted as representing official policies, either expressed
+or implied, of Nic Roets.
diff --git a/bboxSplit.cpp b/bboxSplit.cpp
index f836db1..ca64de9 100755
--- a/bboxSplit.cpp
+++ b/bboxSplit.cpp
@@ -102,6 +102,9 @@ int main (int argc, char *argv[])
       while (n < buf + cnt && isspace (*n)) n++;
       
       if (isEnd && level == 2 && tipe[level - 1] == 'o') { // Note: n may be at buf + cnt
+        nwr[0].clear (); // Free some memory for in case one or more
+        nwr[1].clear (); // processes does heavy postprocessing.
+        nwr[2].clear ();
         for (int j = 0; j < bcnt; j++) fprintf (f[j], "</osm>\n");
         // By splitting these two steps we allow downstream XML converters
         // like gosmore to do their post-XML processing in parallel.
@@ -173,10 +176,12 @@ int main (int argc, char *argv[])
           olevel = level;
         }
       } // If it's /> or </..>
-      else if (*ptr == '<') tipe[level++] = ptr[1];
+      else if (*ptr == '<') {
+        if (ptr[1] != '!') tipe[level++] = ptr[1];
+      }
       // The tests for 'level' is not necessary for valid OSM-XML
       else if (level == 3 && strncasecmp (ptr, "id=", 3) == 0) {
-        id = atoi (ptr[3] == '\'' || ptr[3] == '\"' ? ptr + 4 : ptr + 3);
+        id = atoll (ptr[3] == '\'' || ptr[3] == '\"' ? ptr + 4 : ptr + 3);
       }
       else if (level == 3 && strncasecmp (ptr, "lat=", 4) == 0) {
         lat = atof (ptr[4] == '\'' || ptr[4] == '\"' ? ptr + 5 : ptr + 4);
@@ -188,7 +193,7 @@ int main (int argc, char *argv[])
         memberTipe = ptr[5] == '\'' || ptr[5] == '\"' ? ptr[6] : ptr[5];
       }
       else if (level == 4 && strncasecmp (ptr, "ref=", 4) == 0) {
-        ref = atoi (ptr[4] == '\'' || ptr[4] == '\"' ? ptr + 5 : ptr + 4);
+        ref = atoll (ptr[4] == '\'' || ptr[4] == '\"' ? ptr + 5 : ptr + 4);
       }
       ptr = n;
     } while (ptr + 1 < buf + cnt);
diff --git a/bounds.osm.bz2 b/bounds.osm.bz2
index 56206e7..6bba22b 100755
Binary files a/bounds.osm.bz2 and b/bounds.osm.bz2 differ
diff --git a/dailyUpdate.sh b/dailyUpdate.sh
new file mode 100755
index 0000000..e3602c7
--- /dev/null
+++ b/dailyUpdate.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+# Copyright 2010 Nic Roets as detailed in the README file.
+# The Osm.org Routing demo daily update script
+# The script runs as a cron job.
+
+# make CFLAGS='-O2 -DRES_DIR=\"/usr/share/gosmore/\" -DHEADLESS -DONLY_ROUTING -DLD_CTRL'
+OSMOSIS=$HOME/osmosis-0.38/bin/osmosis
+FIRST_OSC=$(readlink $HOME/planet-latest.osm.bz2 |
+                         sed 's/[^0-9]\|2$//g')
+# A crude way of getting the date of the planet e.g. 100716
+PLANET=$HOME/planet-$FIRST_OSC.osm.bz2
+# List of change files from youngest to oldest
+cd $HOME/daily
+# Get into working directory
+
+if [ g.o -nt lock ] ||
+   ! wget -c http://planet.openstreetmap.org/daily/$(date -d 'now - 1 day' +%Y%m%d)-$(date +%Y%m%d).osc.gz ||
+   ! gzip --test $(date -d 'now - 1 day' +%Y%m%d)-$(date +%Y%m%d).osc.gz
+then exit 0
+fi
+
+cd $HOME/gosmore
+OSC_LIST="ls -r $HOME/daily/*.gz "
+
+# I tried a number of different things (in comments) before I had success.
+# PARAM=$($OSC_LIST |grep -A 30 20${FIRST_OSC}- |
+#     ( read first
+#       echo --rxc $first
+#       awk '{ print "--rxc ", $1, " --mc conflictResolutionMethod=version" }'))
+# CMD="$OSMOSIS $PARAM --rx /dev/stdin --ac --wx -"
+
+#----
+# nice -n 20 $OSMOSIS $PARAM --wxc week.osc
+# exit 0
+# CMD="$OSMOSIS --rxc week.osc --rx /dev/stdin --ac --wx -"
+
+#----
+# PARAM=$($OSC_LIST |grep -A 30 20${FIRST_OSC}- |
+#    ( read first
+#       echo --rxc $first --rx /dev/stdin --ac
+#       awk '{ print "--rxc ", $1, " --ac" }'))
+# CMD="$OSMOSIS $PARAM --wx -"
+
+#----
+PARAM=$($OSC_LIST |grep -B 30 20${FIRST_OSC}- | awk '{ print "--rxc ", $1 }' )
+AC=$($OSC_LIST    |grep -B 30 20${FIRST_OSC}- | awk '{ print "--ac " }')
+
+CMD="$OSMOSIS $PARAM --rx /dev/stdin $AC --wx -"
+
+echo $CMD
+# exit
+
+if nice -n 20 bzcat $PLANET | nice -n 20 $CMD |
+   (cd relations; nice -n 20 ../gosmore sortRelations) |
+   nice -n 20 ./bboxSplit -89 -179 89 -30 "./gosmore rebuild" g.o \
+                         -89 -30 89 179 "cd e; ../gosmore rebuild" europe/g.o
+then mv america/gosmore.pak am.pak
+     mv europe/gosmore.pak eu.pak
+     mv gosmore.pak america/
+     mv e/gosmore.pak europe/
+     mv relations/relations.tbl .
+fi
+
+sleep 2
+touch lock
+./lockMmap $(date +'24*3600 - (%s - 18*3600) %% (24*3600)' |bc) america/gosmore.pak europe/gosmore.pak
diff --git a/default.properties b/default.properties
new file mode 100755
index 0000000..ad4ca32
--- /dev/null
+++ b/default.properties
@@ -0,0 +1,12 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-4
+proguard.config=proguard.cfg
diff --git a/density.c b/density.c
index 33423cb..9691704 100755
--- a/density.c
+++ b/density.c
@@ -24,7 +24,7 @@ char block[S * 2 + 1][98765], *bptr[S * 2 + 1];
 int main (void)
 {
   char fname[30];
-  FILE *html, *gosm = fopen ("bboxes.c", "w"), *sh = fopen ("bboxSplit.sh", "w");
+  FILE *html, *gosm = fopen ("jni/bboxes.c", "w"), *sh = fopen ("bboxSplit.sh", "w");
   memset (cov, 0, sizeof (cov));
   memset (mat, 0, sizeof (mat));
   html= fopen ("density.html", "w");
diff --git a/elemstyles.xml b/elemstyles.xml
index 36ec52e..74088e0 100644
--- a/elemstyles.xml
+++ b/elemstyles.xml
@@ -923,6 +923,15 @@ The colours can only be in hex
 	</rule>
 
 	<rule>
+		<condition k="highway" v="tertiary_link"/>
+		<line width="3" realwidth="6" colour="#fdbf6f"/>
+		<!-- <icon annotate="true" src="misc/deprecated.png" /> -->
+		<scale_min>1</scale_min>
+		<scale_max>40000</scale_max>
+                <routing bicycle="12" foot="5" goods="50" hgv="50" motorcycle="50" motorcar="50" psv="50" moped="45" mofa="25"/>
+	</rule>
+
+	<rule>
 		<condition k="highway" v="unclassified"/>
 		<line width="2" realwidth="5" colour="#c0c0c0"/>
 		<!-- <icon annotate="true" src="misc/deprecated.png" /> -->
@@ -1042,7 +1051,7 @@ The colours can only be in hex
 		<!-- <icon annotate="true" src="misc/deprecated.png" /> -->
         <scale_min>1</scale_min>
         <scale_max>10000</scale_max>
-        <routing bicycle="20" foot="5"/>
+        <routing foot="5"/>
     </rule>
 
     <rule>
@@ -1200,7 +1209,7 @@ The colours can only be in hex
 		<condition k="highway" v="bus_stop" />
 		<icon annotate="true" src="transport/bus_small.png" />
         <scale_min>1</scale_min>
-        <scale_max>50000</scale_max>
+        <scale_max>5000</scale_max>
 	</rule>
 	
 	<rule>
@@ -1434,7 +1443,7 @@ The colours can only be in hex
 		<icon annotate="true" src="nautical/weir.png" />
         <line width="2" colour="#D8D8D8" />
         <scale_min>1</scale_min>
-        <scale_max>50000</scale_max>
+        <scale_max>5000</scale_max>
 	</rule>
 
 	<rule>
@@ -1791,14 +1800,14 @@ The colours can only be in hex
 		<icon annotate="true" src="misc/landmark/power/tower.png" />
         <area width="1" colour="#eeeeee" />
         <scale_min>1</scale_min>
-        <scale_max>50000</scale_max>
+        <scale_max>5000</scale_max>
 	</rule>
 
 	<rule>
 		<condition k="power" v="pole"/>
 		<icon annotate="true" src="misc/landmark/power/pole.png"/>
 		<scale_min>1</scale_min>
-		<scale_max>50000</scale_max>
+		<scale_max>5000</scale_max>
 	</rule>
 
 	<rule>
@@ -1806,7 +1815,7 @@ The colours can only be in hex
         <line width="1" colour="#eeeeee" />
 		<!-- <icon annotate="true" src="misc/deprecated.png" /> -->
         <scale_min>1</scale_min>
-        <scale_max>50000</scale_max>
+        <scale_max>5000</scale_max>
 	</rule>
 
 	<rule>
@@ -1830,7 +1839,7 @@ The colours can only be in hex
 		<icon annotate="true" src="misc/landmark/power.png" />
         <area width="1" colour="#eeeeee" />
         <scale_min>1</scale_min>
-        <scale_max>50000</scale_max>
+        <scale_max>10000</scale_max>
 	</rule>
 
 	<!--the power_source rules must be placed before the power=generator rule! -->
@@ -1839,7 +1848,7 @@ The colours can only be in hex
 		<icon annotate="true" src="misc/landmark/power/wind.png" />
         <area width="1" colour="#eeeeee" />
         <scale_min>1</scale_min>
-        <scale_max>50000</scale_max>
+        <scale_max>5000</scale_max>
 	</rule>
 
 	<rule>
@@ -1890,13 +1899,14 @@ The colours can only be in hex
         <scale_max>50000</scale_max>
 	</rule>
 
+<!-- Rather render according to power_source icons
 	<rule>
-		<condition k="power" v="generator" />
+	<condition k="power" v="generator" />
 		<icon annotate="true" src="misc/landmark/power.png" />
         <area width="1" colour="#eeeeee" />
         <scale_min>1</scale_min>
         <scale_max>50000</scale_max>
-	</rule>
+	</rule> -->
 
 <!--man_made tags -->
 	<rule>
@@ -2057,7 +2067,7 @@ The colours can only be in hex
 		<icon annotate="true" src="leisure/water_park.png" />
         <area colour="#c7f1a3" />		
         <scale_min>1</scale_min>
-        <scale_max>50000</scale_max>
+        <scale_max>20000</scale_max>
 	</rule>
 
 	<rule>
@@ -3126,7 +3136,7 @@ The colours can only be in hex
 		<icon annotate="true" src="shop/toys.png" />
 		<area colour="#a0a0ff"/>
         <scale_min>1</scale_min>
-        <scale_max>65000</scale_max>
+        <scale_max>5000</scale_max>
 	</rule>
 
 	<rule>
diff --git a/gosmore.nsi b/gosmore.nsi
index 35e81fe..3b94765 100755
--- a/gosmore.nsi
+++ b/gosmore.nsi
@@ -15,6 +15,11 @@ UninstPage instfiles
 Section "Gosmore"
   SetOutPath $INSTDIR
   File "gosmore.exe"
+  File "elemstyles.xml"
+  File "icons.csv"
+  File "libgcc_s_dw2-1.dll"
+  File "libstdc++-6.dll"
+  File "libxml2-2.dll"
   File "default.pak"
   File "gosmore.opt"
   File "keepleft.wav"
diff --git a/jni/Android.mk b/jni/Android.mk
new file mode 100755
index 0000000..ef833db
--- /dev/null
+++ b/jni/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+CFLAGS := -g
+
+LOCAL_MODULE := gosmore
+
+LOCAL_CFLAGS := -DANDROID_NDK -DRES_DIR=\"/m8xp2az\"
+
+LOCAL_SRC_FILES := openglespolygon.cpp gosmore.cpp libgosm.cpp 
+
+LOCAL_LDLIBS := -lGLESv1_CM -ldl -llog
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/jni/Application.mk b/jni/Application.mk
new file mode 100755
index 0000000..6ed8cf2
--- /dev/null
+++ b/jni/Application.mk
@@ -0,0 +1,4 @@
+APP_MODULES := gosmore
+APP_PROJECT_PATH := ..
+# APP_STL := gnustl_static
+APP_STL := stlport_static
diff --git a/ConvertUTF.c b/jni/ConvertUTF.c
similarity index 100%
rename from ConvertUTF.c
rename to jni/ConvertUTF.c
diff --git a/ConvertUTF.h b/jni/ConvertUTF.h
similarity index 100%
rename from ConvertUTF.h
rename to jni/ConvertUTF.h
diff --git a/ceglue.c b/jni/ceglue.c
similarity index 100%
rename from ceglue.c
rename to jni/ceglue.c
diff --git a/ceglue.h b/jni/ceglue.h
similarity index 100%
rename from ceglue.h
rename to jni/ceglue.h
diff --git a/gosmore.cpp b/jni/gosmore.cpp
similarity index 75%
rename from gosmore.cpp
rename to jni/gosmore.cpp
index 5473fcf..5fdfac6 100755
--- a/gosmore.cpp
+++ b/jni/gosmore.cpp
@@ -1,11 +1,11 @@
-/* This software is placed by in the public domain by its authors. */
+/* Copyright 2010 Nic Roets as detailed in the README file. */
 /* Written by Nic Roets with contribution(s) from Dave Hansen, Ted Mielczarek
-   David Dean, Pablo D'Angelo and Dmitry.
+   David Dean, Pablo D'Angelo, Dmitry and Adrian Batzill.
    Thanks to
    * Sven Geggus, Frederick Ramm, Johnny Rose Carlsen and Lambertus for hosting,
    * Stephan Rossig, Simon Wood, David Dean, Lambertus and many others for testing,
    * OSMF for partial funding. */
-
+// rm -f obj/local/armeabi/objs/gosmore/gosmore.o.d; ../../../../android/android-ndk-r5/ndk-build
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -18,6 +18,16 @@
 #include <algorithm>
 #include <queue>
 #include <map>
+
+#define LG  //__android_log_print (ANDROID_LOG_WARN, "Gosmore", "%d", __LINE__);
+#ifdef ANDROID_NDK
+#include <android/log.h>
+#include <jni.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#define NOGTK
+#define LOG //__android_log_print (ANDROID_LOG_WARN, "Gosmore", "%d", __LINE__);
+#endif
 using namespace std;
 #ifndef _WIN32
 #include <sys/mman.h>
@@ -36,7 +46,7 @@ using namespace std;
 #ifdef _WIN32_WCE
 #define NOGTK
 #endif
-#ifdef NOGTK
+#if defined(NOGTK) && defined (_WIN32)
 #include <io.h>
 #include <sys/stat.h>
 #include <windowsx.h>
@@ -56,6 +66,9 @@ using namespace std;
 
 #define OLDOLDOPTIONS \
   o (ModelessDialog,  0, 2)
+
+HINSTANCE hInst;
+static HWND   mWnd, dlgWnd = NULL, hwndEdit, button3D, buttons[3];
 #else
 #include <unistd.h>
 #include <sys/stat.h>
@@ -63,6 +76,24 @@ using namespace std;
 #define wchar_t char
 #define wsprintf sprintf
 #endif
+#if !defined (HEADLESS) && !defined (NOGTK)
+#ifdef USE_GNOMESOUND
+#include <libgnome/libgnome.h>
+#endif
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <curl/curl.h>
+#include <curl/easy.h>
+#endif
+#include "openglespolygon.h"
+#ifdef USE_GEOCLUE // Not used and never worked
+#include <geoclue/geoclue-position.h>
+#endif
+#ifdef USE_GPSD
+#include <gps.h>
+#endif
 
 #define OPTIONS \
   o (FollowGPSr,      0, 2) \
@@ -112,32 +143,13 @@ int Display3D = 0; // Not an option but a button for now.
   o (cmduturn, 0, 0) o (cmdround1, 0, 0) o (cmdround2, 0, 0) \
   o (cmdround3, 0, 0) o (cmdround4, 0, 0) o (cmdround5, 0, 0) \
   o (cmdround6, 0, 0) o (cmdround7, 0, 0) o (cmdround8, 0, 0)
-
 char docPrefix[80] = "";
 int GpsIdle=999;
 
-#if !defined (HEADLESS) && !defined (NOGTK)
-#ifdef USE_GNOMESOUND
-#include <libgnome/libgnome.h>
-#endif
-#include <gtk/gtk.h>
-#include <gdk/gdkx.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <curl/curl.h>
-#include <curl/types.h>
-#include <curl/easy.h>
-#endif
-#ifdef USE_GEOCLUE // Not used and never worked
-#include <geoclue/geoclue-position.h>
-#endif
-#ifdef USE_GPSD
-#include <gps.h>
-#endif
 
 // We emulate just enough of gtk to make it work
-#ifdef NOGTK
+#if defined(NOGTK)
 #define gtk_widget_queue_clear(x) // After Click() returns we Invalidate
-HWND hwndList;
 #define gtk_toggle_button_set_active(x,y) // followGPRr
 struct GtkWidget { 
   struct {
@@ -160,10 +172,9 @@ enum { GDK_SCROLL_UP, GDK_SCROLL_DOWN };
 #define VALIDATE_PEN 1
 #define RESERVED_PENS 2 */
 
-HINSTANCE hInst;
-static HWND   mWnd, dlgWnd = NULL, hwndEdit, button3D, buttons[3];
-
+#ifndef ANDROID_NDK
 #define LOG logprintf ("%d\n", __LINE__);
+#endif
 #else
 #define LOG // Less debug info needed because we have gdb
 #ifndef RES_DIR
@@ -189,6 +200,9 @@ const char *FindResource (const char *fname)
   return strdup (fname);
 }
 #endif
+#ifndef HEADLESS
+GtkWidget *draw, *location, *display3D, *followGPSr;
+#endif
 
 // used for showing logs to a file (with default)
 // changed to more suitable value for WinCE in WinMain
@@ -270,19 +284,19 @@ int clon, clat, zoom, option = EnglishNum, gpsSockTag, setLocBusy = FALSE, gDisp
 
 TCHAR currentBbox[80] = TEXT ("");
 
-void ChangePak (const TCHAR *pakfile, int mlon, int mlat)
-{
+int ChangePak (const TCHAR *pakfile, int mlon, int mlat)
+{ // Returns TRUE if pakfile or a bbox was loaded, false if default was loaded or failure
   static int bboxList[][4] = { 
 #include "bboxes.c"
   }, world[] = { -512, -512, 512, 512 }, *bbox = NULL;
-     
+
   if (bbox && bbox[0] <= (mlon >> 22) && bbox[1] <= ((-mlat) >> 22) &&
-              bbox[2] >  (mlon >> 22) && bbox[3] >  ((-mlat) >> 22)) return;
-  GosmFreeRoute ();
+              bbox[2] >  (mlon >> 22) && bbox[3] >  ((-mlat) >> 22)) return 0;
+  LG GosmFreeRoute ();
   memset (gosmSstr, 0, sizeof (gosmSstr));
   shortest = NULL;
         
-  if (!pakfile) {
+  LG if (!pakfile) {
     int best = 0;
     for (size_t j = 0; j < sizeof (bboxList) / sizeof (bboxList[0]); j++) {
       int worst = min (mlon / 8 - (bboxList[j][0] << 19),
@@ -335,13 +349,14 @@ void ChangePak (const TCHAR *pakfile, int mlon, int mlat)
     CreateFileMapping(gmap, NULL, PAGE_READONLY, 0, 0, 0);
   LOG map = fm == INVALID_HANDLE_VALUE ? NULL :
     MapViewOfFile (fm, FILE_MAP_READ, 0, 0, 0);
+  int len = map ? GetFileSize (gmap, NULL) : 0;
   LOG Exit = !map || !GosmInit (map, GetFileSize(gmap, NULL));
   LOG if (Exit && gmap != INVALID_HANDLE_VALUE) {
     MessageBox (NULL, TEXT ("mmap problem. Pak file too big ?"),
       TEXT (""), MB_APPLMODAL|MB_OK);
   }
 
-  #if 0
+  #ifdef _WIN32
   FILE *gmap = _wfopen (/*"./gosmore.pak"*/ , TEXT ("rb"));
 
   if (!gmap) {
@@ -364,43 +379,62 @@ void ChangePak (const TCHAR *pakfile, int mlon, int mlat)
 //  printf ("%s %d %d\n", pakfile, (mlon >> 22) + 512, 512 - (mlat >> 22));
   if (map != (void*) -1) munmap (map, len);
   
-  FILE *gmap = fopen64 (pakfile, "r");
-  if (!gmap && currentBbox == pakfile &&
-             (gmap = fopen64 ("default.pak", "r")) == NULL) {
+  FILE *pakmap = fopen64 (pakfile, "r");
+  FILE *gmap = !pakmap && currentBbox == pakfile
+                  ? fopen64 ("default.pak", "r") : pakmap;
+  if (!gmap && currentBbox == pakfile) {
     gmap = fopen64 (RES_DIR "default.pak", "r");
   }
-  len = gmap && fseek (gmap, 0, SEEK_END) == 0 ? ftell (gmap) : 0;
+  LG len = gmap && fseek (gmap, 0, SEEK_END) == 0 ? ftell (gmap) : 0;
   map = !len ? (void*)-1
      : mmap (NULL, ftell (gmap), PROT_READ, MAP_SHARED, fileno (gmap), 0);
-  Exit = map == (void *) -1 || !GosmInit (map, len);
-  if (gmap) fclose (gmap);
+  LG Exit = map == (void *) -1 || !GosmInit (map, len);
+  LG if (gmap) fclose (gmap);
   #endif
   /* // Slightly more portable:
   GMappedFile *gmap = g_mapped_file_new (pakfile, FALSE, NULL);
   Exit = !gmap || !GosmInit (g_mapped_file_get_contents (gmap),
       g_mapped_file_get_length (gmap));
   */
+//  __android_log_print(ANDROID_LOG_WARN, "Gosmore", "re %p %d", bbox, Exit);
   LOG if (Exit) bbox = NULL;
+  LG return pakmap != NULL;
+}
+#ifdef ANDROID_NDK
+extern "C" jint Java_org_osmu_gosmore_MapActivity_changePak (JNIEnv*  env,
+    jobject thiz, jstring js, jint mlon, jint mlat)
+{
+  LG IconSet = 1;
+  DetailLevel = 3;
+  ButtonSize = 4;
+  Background = 1;
+  option= mapMode;
+  ShowCompass = 0;
+  const char *sdcard = env->GetStringUTFChars(js, NULL);
+  chdir (sdcard);
+  LG env->ReleaseStringUTFChars(js, sdcard);
+  if (ChangePak ("gosmore.pak", 0, 0)) return 2;
+  if (Exit && ChangePak (NULL, mlon, mlat)) return 2;
+  if (Exit) strcpy (currentBbox, "default");
+//  __android_log_print(ANDROID_LOG_WARN, "Gosmore", "re %s", currentBbox);
+  return Exit ? 0 : 1;
+}
+
+extern "C" jstring Java_org_osmu_gosmore_Update_currentBbox
+                       (JNIEnv* env, jobject thiz)
+{
+//  __android_log_print(ANDROID_LOG_WARN, "Gosmore", "re %s", currentBbox);
+  currentBbox[16] = '\0'; // Strip the .pak off for Java
+  return env->NewStringUTF (currentBbox);
 }
 
+#endif
+
 #ifndef HEADLESS
 
-GtkWidget *draw, *location, *display3D, *followGPSr;
 double cosAzimuth = 1.0, sinAzimuth = 0.0;
 string highlight, searchStr ("Search");
 
-struct tsItem {
-  string cmd;
-  #ifndef NOGTK
-  GdkPixbuf *pix;
-  #else
-  HICON pix;
-  #endif
-//  tsItem () {}
-};
-
-deque<tsItem> tsList;
-
 inline void SetLocation (int nlon, int nlat)
 {
   clon = nlon;
@@ -409,6 +443,7 @@ inline void SetLocation (int nlon, int nlat)
   char lstr[50];
   int zl = 0;
   while (zl < 32 && (zoom >> zl)) zl++;
+  setlocale (LC_NUMERIC, "C");
   sprintf (lstr, "?lat=%.5lf&lon=%.5lf&zoom=%d", LatInverse (nlat),
     LonInverse (nlon), 33 - zl);
   setLocBusy = TRUE;
@@ -424,6 +459,7 @@ int ChangeLocation (void)
   char *lstr = (char *) gtk_entry_get_text (GTK_ENTRY (location));
   double lat, lon;
   while (*lstr != '?' && *lstr != '\0') lstr++;
+  setlocale (LC_NUMERIC, "C");
   if (sscanf (lstr, "?lat=%lf&lon=%lf&zoom=%d", &lat, &lon, &zoom) == 3) {
     clat = Latitude (lat);
     clon = Longitude (lon);
@@ -674,6 +710,8 @@ void CallRoute (int recalculate, int plon, int plat)
   #endif
 }
 
+
+#ifndef ANDROID_NDK
 void DoFollowThing (gpsNewStruct *gps)
 {
   static int lastTime = -1;
@@ -711,18 +749,60 @@ void DoFollowThing (gpsNewStruct *gps)
   }
   if (!/*gps->fix.mode >= MODE_2D &&*/ FollowGPSr) return;
   SetLocation (Longitude (gps->fix.longitude), Latitude (gps->fix.latitude));
-/*    int plon = Longitude (gps->fix.longitude + gps->fix.speed * 3600.0 /
-      40000000.0 / cos (gps->fix.latitude * (M_PI / 180.0)) *
-      sin (gps->fix.track * (M_PI / 180.0)));
-    int plat = Latitude (gps->fix.latitude + gps->fix.speed * 3600.0 /
-      40000000.0 * cos (gps->fix.track * (M_PI / 180.0))); */
+  __int64 dlon = clon - flon, dlat = clat - flat;
+  flon = clon;
+  flat = clat;
+#else
+
+extern "C" void Java_org_osmu_gosmore_MapRenderer_startRoute (
+  JNIEnv*  env, jobject thiz, jdouble lon, jdouble lat)
+{
+  flon = Longitude (lon);
+  flat = Latitude (lat);
+  GosmFreeRoute ();
+  shortest = NULL;
+}
+
+extern "C" void Java_org_osmu_gosmore_MapRenderer_endRoute (
+  JNIEnv*  env, jobject thiz, jdouble lon, jdouble lat, jboolean fastest,
+  jint vehicle)
+{
+  tlon = Longitude (lon);
+  tlat = Latitude (lat);
+  Vehicle = vehicle;
+  FastestRoute = fastest;
+  Route (TRUE, 0, 0, Vehicle, FastestRoute);
+}
+
+extern "C" jint Java_org_osmu_gosmore_MapRenderer_doRoute (
+  JNIEnv*  env, jobject thiz)
+{
+  if (!RouteLoop()) return routeSuccess ? 999 : -1;
+  // I suspect shortest is never NULL here, but I still guard against it.
+  return (jint)(!shortest ? 0 : ((Sqr (__int64 (shortest->nd->lon - tlon)) +
+    Sqr (__int64 (shortest->nd->lat - tlat))) * 100) /
+    (Sqr (__int64 (flon - tlon)) +
+     Sqr (__int64 (flat - tlat)) + (1<<15)));
+}
+
+extern "C" jstring Java_org_osmu_gosmore_MapRenderer_navigate (
+  JNIEnv*  env, jobject thiz, jdouble lon, jdouble lat, jfloat speed,
+  jfloat bearing)
+{
+  const char *tts = "";
+  flon = Longitude (lon);
+  flat = Latitude (lat);
+  __int64 dlon = Longitude (lon + speed * 3600.0 /
+      40000000.0 / cos (lat * (M_PI / 180.0)) *
+      sin (bearing * (M_PI / 180.0))) - flon;
+  __int64 dlat = Latitude (lat + speed * 3600.0 /
+      40000000.0 * cos (bearing * (M_PI / 180.0))) - flat;
+  // Slightly faster would be dlon=speed*(...); dlat=speed*(...);
+#endif
     // Predict the vector that will be traveled in the next 10seconds
 //    printf ("%5.1lf m/s Heading %3.0lf\n", gps->fix.speed, gps->fix.track);
 //    printf ("%lf %lf\n", gps->fix.latitude, gps->fix.longitude);
     
-  __int64 dlon = clon - flon, dlat = clat - flat;
-  flon = clon;
-  flat = clat;
   if (routeSuccess) CallRoute (FALSE, dlon, dlat);
 
   static ndType *decide[3] = { NULL, NULL, NULL }, *oldDecide = NULL;
@@ -763,7 +843,7 @@ void DoFollowThing (gpsNewStruct *gps)
           x->shortest->shortest ? x->shortest->shortest->nd->lon : tlon;
         while (nd[-1].lon == nd->lon && nd[-1].lat == nd->lat) nd--;
         int segCnt = 0; // Count number of segments at x->shortest
-        int n2Left, fLeft = INT_MIN;
+        int n2Left = /* Keep compiler quiet*/ 0, fLeft = INT_MIN;
         do {
           // TODO : Only count segment traversable by 'Vehicle'
           // Except for the case where a cyclist crosses a motorway_link.
@@ -819,7 +899,20 @@ void DoFollowThing (gpsNewStruct *gps)
     oldCommand = command[0];
     oldDecide = decide[0];
     #define o(cmd,dummy1,dummy2) TEXT (#cmd),
-#ifdef _WIN32_WCE
+#ifdef ANDROID_NDK
+    static const char *cmds[] = {
+    "Turn left.", "Keep left.", "Turn right", "Keep right.",
+    "You have reached your destination.", "Make a U turn if possible.",
+    "At the roundabout, take the first exit.",
+    "At the roundabout, take the second exit.",
+    "At the roundabout, take the third exit.",
+    "At the roundabout, take the fourth exit.",
+    "At the roundabout, take the fifth exit.",
+    "At the roundabout, take the sixth exit.",
+    "At the roundabout, take the seventh exit.",
+    "At the roundabout, take the eighth exit." };
+    tts = cmds[command[0]-cmdturnleftNum];
+#elif defined(_WIN32_WCE)
     static const wchar_t *cmdStr[] = { COMMANDS };
     wchar_t argv0[80];
     GetModuleFileName (NULL, argv0, sizeof (argv0) / sizeof (argv0[0]));
@@ -852,21 +945,66 @@ void DoFollowThing (gpsNewStruct *gps)
     sinAzimuth = -dlon / dist;
   }                                            
   gtk_widget_queue_clear (draw);
+  #ifdef ANDROID_NDK
+  return env->NewStringUTF( tts);
+  #endif
 } // If following the GPSr and it has a fix.
 
+// Regrettably here are a few static variables with very generic names. They
+// are however unique in this file.
+static int cosa, sina, xadj, width = 320, height = 240;
+__int64 yadj;
+#define FAR3D  100000 // 3D view has a limit of roughly 5 km forwards
+#define WIDE3D 100000 // and roughly 5km between top left & top right corner
+#define CAMERA2C 20000 // How far the camera is behind the user (clat/lon)
+#define HEIGHT   12000 // Height of the camera
+#define PIX45     256 // Y value corresponding to 45 degrees down
+#define XFix PIX45
+
+#define myint int
+/* The 3D computations can all be done in signed 32 bits integers,
+   provided overflow bits are simply discarded. The C specification says
+   however that ints that overflow are undefined (as well as any
+   expression that touches them). So if the 3D display looks garbled
+   under a new compiler, try running with #define myint __int64
+*/
+
+#define MUL 64
+#define Depth(lon,lat) \
+           (int)(yadj + (lat) * (myint) cosa - (lon) * (myint) sina)
+#define X1(lon,lat) \
+           (int)(xadj + (lon) * (myint) cosa + (lat) * (myint) sina)
+#define AdjDepth(lon,lat) (Depth (lon, lat) < PIX45 * HEIGHT * MUL / 5000 \
+                      && Depth (lon, lat) > -PIX45 * HEIGHT * MUL / 5000 ? \
+                         PIX45 * HEIGHT * MUL / 5000 : Depth (lon, lat))
+#define Y(lon,lat) (Display3D ? PIX45 * HEIGHT * MUL / AdjDepth (lon, lat) \
+     : yadj + (int)(((lon) * (__int64) sina - (lat) * (__int64) cosa) >> 32))
+#define Y2(lon,lat) (Display3D ? PIX45 * HEIGHT * MUL * (__int64)65536 / AdjDepth (lon, lat) \
+ : (yadj<<16) + (int)(((lon) * (__int64) sina - (lat) * (__int64) cosa) >> 16))
+#define X(lon,lat) (Display3D ? width / 2 + \
+((AdjDepth (lon, lat) > 0 ? 1 : -1) * \
+  (X1 (lon, lat) / 32000 - AdjDepth (lon, lat) / XFix) > 0 ? 32000 : \
+(AdjDepth (lon, lat) > 0 ? 1 : -1) * \
+  (X1 (lon, lat) / 32000 + AdjDepth (lon, lat) / XFix) < 0 ? -32000 : \
+X1(lon,lat) / (AdjDepth (lon, lat) / XFix)) \
+: xadj + (int)(((lon) * (__int64) cosa + (lat) * (__int64) sina) >> 32))
+#define X2(lon,lat) (Display3D ? X(lon,lat)*65536 : \
+   (xadj<<16) + (int)(((lon) * (__int64) cosa + (lat) * (__int64) sina) >> 16))
+//X2 and Y2 are X and Y but 65536 times larger
+
 #ifndef NOGTK
 #ifdef ROUTE_TEST
 gint RouteTest (GtkWidget * /*widget*/, GdkEventButton *event, void *)
 {
   static int ptime = 0;
   ptime = time (NULL);
-  int w = draw->allocation.width;
+  int w = width;
   int perpixel = zoom / w;
   clon += lrint ((event->x - w / 2) * perpixel);
-  clat -= lrint ((event->y - draw->allocation.height / 2) * perpixel);
+  clat -= lrint ((event->y - height / 2) * perpixel);
 /*    int plon = clon + lrint ((event->x - w / 2) * perpixel);
     int plat = clat -
-      lrint ((event->y - draw->allocation.height / 2) * perpixel); */
+      lrint ((event->y - height / 2) * perpixel); */
   FollowGPSr = TRUE;
   gpsNewStruct gNew;
   gNew.fix.latitude = LatInverse (clat);
@@ -927,7 +1065,7 @@ void GpsMove (gps_data_t *gps, char */*buf*/, size_t /*len*/
 }*/
 #endif // !ROUTE_TEST
 
-#else // else NOGTK
+#elif defined(_WIN32) // else NOGTK
 #define NEWWAY_MAX_COORD 10
 struct newWaysStruct {
   int coord[NEWWAY_MAX_COORD][2], klas, cnt, oneway, bridge;
@@ -1011,6 +1149,7 @@ BOOL CALLBACK DlgSetTags2Proc (HWND hwnd, UINT Msg, WPARAM wParam,
 
 #endif // NOGTK
 
+#ifndef ANDROID_NDK
 int Scroll (GtkWidget * /*widget*/, GdkEventScroll *event, void * /*w_cur*/)
 {
   if (Display3D) {
@@ -1019,7 +1158,7 @@ int Scroll (GtkWidget * /*widget*/, GdkEventScroll *event, void * /*w_cur*/)
                  clat + lrint (cosAzimuth * k));
   }
   else {
-    int w = draw->allocation.width, h = draw->allocation.height;
+    int w = width, h = height;
     int perpixel = zoom / w;
     if (event->direction == GDK_SCROLL_UP) zoom = zoom / 4 * 3;
     if (event->direction == GDK_SCROLL_DOWN) zoom = zoom / 3 * 4;
@@ -1031,6 +1170,7 @@ int Scroll (GtkWidget * /*widget*/, GdkEventScroll *event, void * /*w_cur*/)
   gtk_widget_queue_clear (draw);
   return FALSE;
 }
+#endif
 
 int objectAddRow = -1;
 #define ADD_HEIGHT 32
@@ -1039,7 +1179,7 @@ void HitButton (int b)
 {
   int returnToMap = b > 0 && option <= FastestRouteNum;
   
-  #ifdef NOGTK
+  #ifdef _WIN32
   if (AddWayOrNode && b == 0) {
     AddWayOrNode = 0;
     option = mapMode;
@@ -1063,7 +1203,7 @@ void HitButton (int b)
     tlat = clat;
     CallRoute (TRUE, 0, 0);
   }
-  #ifdef NOGTK
+  #ifdef _WIN32
   else if (option == DisplayOffNum) {
     if (CeEnableBacklight(FALSE)) {
       gDisplayOff = TRUE;
@@ -1088,8 +1228,6 @@ void HitButton (int b)
   if (returnToMap) option = mapMode;
 }
 
-int firstDrag[2] = { -1, -1 }, lastDrag[2], pressTime;
-
 #ifndef NOGTK
 struct wayPointStruct {
   int lat, lon;
@@ -1169,14 +1307,15 @@ int UpdateWayPoints (GtkWidget *, GdkEvent *, gpointer *)
   return FALSE;
 }
 
-gint Drag (GtkWidget * /*widget*/, GdkEventMotion *event, void * /*w_cur*/)
+//gint Drag (GtkWidget * /*widget*/, GdkEventMotion *event, void * /*w_cur*/)
+/*
 {
   if ((option == mapMode || option == optionMode) &&
           (event->state & GDK_BUTTON1_MASK)) {
     if (firstDrag[0] >= 0) gdk_draw_drawable (draw->window,
       draw->style[0].fg_gc[0], draw->window, 
       0, 0, lrint (event->x) - lastDrag[0], lrint (event->y) - lastDrag[1],
-      draw->allocation.width, draw->allocation.height);
+      width, height);
     lastDrag[0] = lrint (event->x);
     lastDrag[1] = lrint (event->y);
     if (firstDrag[0] < 0) {
@@ -1185,7 +1324,7 @@ gint Drag (GtkWidget * /*widget*/, GdkEventMotion *event, void * /*w_cur*/)
     }
   }
   return FALSE;
-}
+}*/
 
 GtkWidget *bar;
 int UpdateProcessFunction(void */*userData*/, double t, double d,
@@ -1200,7 +1339,6 @@ int UpdateProcessFunction(void */*userData*/, double t, double d,
 void *UpdateMapThread (void *n)
 {
   CURL *curl;
-  CURLcode res;
   FILE *outfile;
  
   curl = curl_easy_init();
@@ -1217,10 +1355,10 @@ void *UpdateMapThread (void *n)
     curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, UpdateProcessFunction);
     curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, ""); // Bar);
  
-    res = curl_easy_perform(curl);
+    curl_easy_perform(curl);
  
     fclose(outfile);
-    system ("unzip tmp.zip"); //cmd.c_str ());
+    if (system ("unzip tmp.zip") == -1) fprintf (stderr, "Error:system()\n");
     string dst ((string)(char*)n + ".pak");
     rename ("gosmore.pak", dst.c_str ());
     unlink ("tmp.zip");
@@ -1309,20 +1447,42 @@ DWORD WINAPI UpdateMapThread (LPVOID n)
 }
 #endif
 
-#define CompactOptions ((draw->allocation.width * draw->allocation.height < 400 * 400))
+/* These macros calling macros may result in very long bloated code and
+   inefficient machine code, depending on how well the compiler optimizes.
+*/
+
+#define CompactOptions ((width * height < 400 * 400))
 int ListXY (int cnt, int isY)
 { // Returns either the x or the y for a certain list item
   int max = mapMode; //option == optionMode ? mapNode :
   int w = CompactOptions ? 70 : 105, h = CompactOptions ? 45 : 80;
-  while ((draw->allocation.width/w) * (draw->allocation.height/h - 1) > max) {
+  while ((width/w) * (height/h - 1) > max) {
     w++;
     h++;
   }
-  return isY ? cnt / (draw->allocation.width / w) * h + h / 2 - listYOffset :
-    (cnt % (draw->allocation.width / w)) * w + w / 2;
+  return isY ? cnt / (width / w) * h + h / 2 - listYOffset :
+    (cnt % (width / w)) * w + w / 2;
 }
 
-#ifndef NOGTK
+#ifdef ANDROID_NDK // OPENGL
+typedef jint HDC;
+#define gdk_draw_drawable(win,dgc,sdc,x,y,dx,dy,w,h) \
+	do { int crop[] = { x, y + h, w, -h }; \
+	glEnable(GL_BLEND); \
+	glEnable(GL_TEXTURE_2D); \
+	glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); \
+	glDrawTexiOES(dx, height - dy, 0, crop[2], h); \
+	glDisable(GL_TEXTURE_2D); \
+	glDisable(GL_BLEND);\
+	} while (0) // TODO Try to get a glMatrix that match OES coordinates
+#define gdk_draw_line(win,gc,sx,sy,dx,dy) \
+  do { GdkPoint l[2] = { sx, sy, dx, dy }; \
+    glVertexPointer (2, GL_SHORT, 0, l); \
+    glDrawArrays (GL_LINES, 0, 2); } while (0)
+
+static jmethodID drawTeks = 0;
+
+#elif !defined(NOGTK)
 typedef GdkGC *HDC;
 
 static GdkGC *maskGC = NULL, *fg_gc;
@@ -1355,13 +1515,13 @@ PangoLayout  *pl;
 
 void DrawString (int x, int y, const char *optStr)
 {
-  #if PANGO_VERSION
+  #ifdef PANGO_VERSION
   PangoMatrix mat = PANGO_MATRIX_INIT;
   pango_context_set_matrix (pc, &mat);
   pango_layout_set_text (pl, optStr, -1);
   gdk_draw_layout (GDK_DRAWABLE (draw->window),
                      fg_gc /*draw->style->fg_gc[0]*/, x, y, pl);
-  #else
+  #elif defined (_WIN32)
   SelectObject (mygc, sysFont);
   const unsigned char *sStart = (const unsigned char*) optStr;
   UTF16 wcTmp[70], *tStart = (UTF16 *) wcTmp;
@@ -1376,9 +1536,9 @@ void DrawString (int x, int y, const char *optStr)
 void DrawPoI (int dstx, int dsty, int *icon)
 {
   if (icon[2] == 0 || dstx < -icon[2] || dsty < -icon[3] ||
-    dstx > draw->allocation.width + icon[2] ||
+    dstx > width + icon[2] ||
     // GDK need these tests for the Start&EndRoute markers
-    dsty > draw->allocation.height + icon[3]) return;
+    dsty > height + icon[3]) return;
   #ifndef NOGTK
   // for gdk we first need to extract the portion of the mask
   if (!maskicon) maskicon = gdk_pixmap_new(NULL, 100, 100, 1);
@@ -1411,7 +1571,94 @@ void GeoSearch (const char *key)
   else GosmSearch (clon, clat, key);
 }
 
-int HandleKeyboard (GdkEventButton *event)
+
+#if defined (ANDROID_NDK)
+/*extern "C" void Java_org_osmu_gosmore_MapView_setLocation (
+		JNIEnv*  env, jobject thiz, jdouble lon, jdouble lat)
+{
+  LG clon = Longitude (lon);
+  clat = Latitude (lat);
+}*/
+
+#define DisplaySearchResults(); // Never in searchMode, no-op
+extern "C" void Java_org_osmu_gosmore_Search_search (
+		JNIEnv*  env, jobject thiz, jstring jquery)
+{
+	static jmethodID meth = 0;
+	static int started = 0;
+	if (!started) {
+	  started = 1;
+	  jclass cls=env->GetObjectClass(thiz);
+	  //cls =(jclass)( env->NewGlobalRef(jcls) );
+      //cls = env->FindClass(
+	//		  "org/osmu/gosmore/MyClb");
+
+	  meth = env->GetMethodID(cls, "searchResult",
+			  "(IIIIDIILjava/lang/String;DDI)V");
+//	  env->ExceptionClear();
+	  /*  if (method != 0)*/
+//	    env->ExceptionClear();
+	}
+	const char *query = env->GetStringUTFChars(jquery, NULL);
+	GeoSearch (query);
+	LG env->ReleaseStringUTFChars(jquery, query);
+
+#else
+void DisplaySearchResults (void)
+{
+#endif
+	    for (int i = 0, y = SearchSpacing / 2; i < searchCnt && gosmSstr[i];
+	             i++, y += SearchSpacing) {
+	      double dist = sqrt (double (Sqr ((__int64) clon - gosmSway[i]->clon) +
+	          Sqr ((__int64) clat - gosmSway[i]->clat))) * (20000 / 2147483648.0) *
+	        cos (LatInverse (clat) * (M_PI / 180));
+
+	      int x = SearchSpacing + 70;
+	      __int64 lx = X (gosmSway[i]->clon, gosmSway[i]->clat) - width / 2;
+	      __int64 ly = Y (gosmSway[i]->clon, gosmSway[i]->clat) - height / 2;
+	      double norm = lx || ly ? sqrt (double(lx * lx + ly * ly)) / 64 : 1;
+	      int u = lrint (lx / norm), v = lrint (ly / norm);
+	      string s (gosmSstr[i], strcspn (gosmSstr[i], "\n"));
+	      char *name = (char *)(gosmSway[i] + 1) + 1;
+	      if (name != gosmSstr[i]) s += " (" +
+	                     string (name, strcspn (name, "\n")) + ")";
+	      #ifdef ANDROID_NDK
+	      jstring js = env->NewStringUTF (s.c_str ());
+	      int *z = Style (gosmSway[i])->x + 4 * IconSet;
+              env->CallVoidMethod (thiz, meth, z[0], z[1], z[2], z[3],
+                          dist, u, v, js,
+        		  LonInverse (gosmSway[i]->clon),
+        		  LatInverse (gosmSway[i]->clat),
+        		  gosmSway[i]->dlat + gosmSway[i]->dlon + (1 << 15));
+	      #else
+	      DrawPoI (SearchSpacing / 2, y, Style (gosmSway[i])->x + 4 * IconSet);
+
+	      char distance[10]; // Formula inaccurate over long distances hence "Far"
+	      sprintf (distance, dist > 998 ? "Far" : dist > 1 ? "%.0lf km" :
+	        "%.0lf m", dist > 1 ? dist : dist * 1000);
+	      DrawString (SearchSpacing + 33 - 11 * strcspn (distance, " "), y - 10,
+	        distance); // Right adjustment is inaccurate
+	      gdk_draw_line (draw->window, mygc, x + u / 8, y + v / 8,
+	        x - u / 8, y - v / 8);
+	      gdk_draw_line (draw->window, mygc, x + u / 8, y + v / 8,
+	        x + u / 12 + v / 20, y - u / 20 + v / 12);
+	      gdk_draw_line (draw->window, mygc, x + u / 8, y + v / 8,
+	        x + u / 12 - v / 20, y + u / 20 + v / 12);
+
+	      DrawString (SearchSpacing + x, y - 10, s.c_str ());
+
+	      gdk_draw_line (draw->window, mygc, 0, y + SearchSpacing / 2,
+	        width, y + SearchSpacing / 2);
+	      #endif
+	    }
+}
+
+
+#ifndef _WIN32_WCE
+int HandleKeyboard (int, int, int)
+{
+#else
+int HandleKeyboard (int event, int ex, int ey)
 { // Some WinCE devices, like the Mio Moov 200 does not have an input method
   // and any call to activate it or set the text on an EDIT or STATIC (label)
   // control will crash the application. So under WinCE we default to our
@@ -1420,13 +1667,12 @@ int HandleKeyboard (GdkEventButton *event)
   // Draw our own keyboard (Expose Event) or handle the key (Click)
   if (Keyboard) return FALSE; // Using the Windows keyboard
   // DrawString (30, 5, searchStr.c_str ()); // For testing under GTK
-  #ifdef _WIN32_WCE
   if (!event) {
     RECT r;
     r.left = 0;
-    r.top = draw->allocation.height - 32 * 3;
-    r.right = draw->allocation.width;
-    r.bottom = draw->allocation.height;
+    r.top = height - 32 * 3;
+    r.right = width;
+    r.bottom = height;
     FillRect (mygc, &r, (HBRUSH) GetStockObject (WHITE_BRUSH)); //brush[KeyboardNum]);
     SelectObject (mygc, GetStockObject (BLACK_PEN));
   }
@@ -1434,9 +1680,9 @@ int HandleKeyboard (GdkEventButton *event)
   const char *kbLayout[] = { "qwertyuiop", "asdfghjkl", " zxcvbnm,$" };
   for (int i = 0; i < 3; i++) {
     for (int j = 0; kbLayout[i][j] != '\0'; j++) {
-      int hb = draw->allocation.width / strlen (kbLayout[0]) / 2, ys = 16;
-      int x = (2 * j + (i & 1)) * hb, y = draw->allocation.height - (3 - i) * ys * 2;
-      if (event && event->y >= y && event->y < y + ys + ys && event->x < x + hb + hb) {
+      int hb = width / strlen (kbLayout[0]) / 2, ys = 16;
+      int x = (2 * j + (i & 1)) * hb, y = height - (3 - i) * ys * 2;
+      if (event && ey >= y && ey < y + ys + ys && ex < x + hb + hb) {
         if (kbLayout[i][j] != '$') searchStr += kbLayout[i][j];
         else if (searchStr.length () > 0) searchStr.erase (searchStr.length () - 1, 1);
         logprintf ("'%s'\n", searchStr.c_str());
@@ -1446,7 +1692,7 @@ int HandleKeyboard (GdkEventButton *event)
       }
       if (!event) {
         if (j > 0) gdk_draw_line (draw->window, mygc, x, y, x, y + ys + ys);
-        else gdk_draw_line (draw->window, mygc, 0, y, draw->allocation.width, y);
+        else gdk_draw_line (draw->window, mygc, 0, y, width, y);
         string chr = string ("") + kbLayout[i][j];
         if (kbLayout[i][j] == ' ') DrawString (x + hb - 5, y + ys / 2, "[ ]");
         else if (kbLayout[i][j] != '$') DrawString (x + hb, y + ys / 2, chr.c_str ());
@@ -1462,29 +1708,56 @@ int HandleKeyboard (GdkEventButton *event)
   return FALSE;
 }
 
-int Click (GtkWidget * /*widget*/, GdkEventButton *event, void * /*para*/)
-{
-  static int lastRelease = 0;
-  int w = draw->allocation.width, h = draw->allocation.height;
+static int lastRelease = 0, oldx = -1, oldy, pressTime = -1;
 
+#if !defined (ANDROID_NDK)
+/*extern "C" int Java_org_osmu_gosmore_MapRenderer_mouseEv (
+		JNIEnv*  env, jobject thiz, jint x, jint y, jint evTime,
+		jint button, jboolean click)*/
+int MouseEv (int x, int y, int evTime, int button, int click)
+{
   // Anything that covers more than 3 pixels in either direction is a drag.
-  int isDrag = DebounceDrag
-        ? firstDrag[0] >= 0 && (lastRelease + 100 > (int) event->time ||
-                                  pressTime + 100 < (int) event->time)
-        : firstDrag[0] >= 0 && (abs((int)(firstDrag[0] - event->x)) > 3 ||
-                                abs((int)(firstDrag[1] - event->y)) > 3);
-  
+  LG gtk_widget_queue_clear (draw); 
+  int w = width, h = height;
+  int isDrag = //DebounceDrag ?
+        pressTime >= 0 && (lastRelease + 200 > evTime ||
+                                pressTime + 200 < evTime);
+//        : pressTime >= 0 && (abs((int)(firstDrag[0] - event->x)) > 3 ||
+//                                abs((int)(firstDrag[1] - event->y)) > 3;
   // logprintf("Click (isDrag = %d): firstDrag = %d,%d; event = %d,%d\n",
   // 	    isDrag, firstDrag[0], firstDrag[1], event->x, event->y);
+  if (pressTime == -1) pressTime = evTime;
+  if (click) pressTime = -1;
+  if (click) lastRelease = evTime;
+  if (isDrag) {
+    if (option == optionMode) {
+      listYOffset = max (0, listYOffset + (int)lrint (oldy - y));
+    }
+    if (option == mapMode) {
+      int lon = clon + lrint (zoom / w *
+        (cosAzimuth * (Display3D ? 0 : oldx - x) - sinAzimuth * (y - oldy)));
+      int lat = clat + lrint (zoom / w *
+        (cosAzimuth * (y - oldy + sinAzimuth * (Display3D ? 0 : oldx - x))));
+      if (Display3D) {
+        double newa = atan2 (sinAzimuth, cosAzimuth) - (oldx-x) * M_PI / 580;
+        cosAzimuth = cos (newa);
+        sinAzimuth = sin (newa);
+      }
+      SetLocation (lon, lat);
+    }
+  }
+  oldx = x;
+  oldy = y;
+  if (!click || isDrag) return 0;
 
   if (ButtonSize <= 0) ButtonSize = 4;
-  int b = (draw->allocation.height - lrint (event->y)) / (ButtonSize * 20);
+  int b = (height - lrint (y)) / (ButtonSize * 20);
   if (objectAddRow >= 0) {
     int perRow = (w - ButtonSize * 20) / ADD_WIDTH;
-    if (event->x < w - ButtonSize * 20) {
-      #ifdef NOGTK
-      newWays[newWayCnt].klas = objectAddRow + event->x / ADD_WIDTH +
-                                event->y / ADD_HEIGHT * perRow;
+    if (x < w - ButtonSize * 20) {
+      #ifdef _WIN32
+      newWays[newWayCnt].klas = objectAddRow + x / ADD_WIDTH +
+                                y / ADD_HEIGHT * perRow;
       SipShowIM (SIPF_ON);
       if (DialogBox (hInst, MAKEINTRESOURCE (IDD_SETTAGS), NULL,
           (DLGPROC) DlgSetTagsProc)) {} //DialogBox (hInst,
@@ -1493,20 +1766,17 @@ int Click (GtkWidget * /*widget*/, GdkEventButton *event, void * /*para*/)
       #endif
       objectAddRow = -1;
     }
-    else objectAddRow = int (event->y) * (restriction_no_right_turn / perRow
-                                  + 2) / draw->allocation.height * perRow;
+    else objectAddRow = y * (restriction_no_right_turn / perRow + 2) /
+                              height * perRow;
   }
-  else if (event->x > w - ButtonSize * 20 && b <
+  else if (x > w - ButtonSize * 20 && b <
       (Layout >
        (MenuKey == 0 || option != mapMode ? 0 : 1) ? 3 : 0)) HitButton (b);
   else if (option == optionMode) {
-    if (isDrag) {
-      listYOffset = max (0, listYOffset + (int)lrint (firstDrag[1]-event->y));
-    }
-    else {
+    if (1) {
       for (int best = 9999, i = 0; i < mapMode; i++) {
-        int d = lrint (fabs (ListXY (i, FALSE) - event->x) +
-                       fabs (ListXY (i, TRUE) - event->y));
+        int d = lrint (fabs (double(ListXY (i, FALSE) - x)) +
+                       fabs (double(ListXY (i, TRUE) - y)));
         if (d < best) {
           best = d;
           option = i;
@@ -1517,6 +1787,7 @@ int Click (GtkWidget * /*widget*/, GdkEventButton *event, void * /*para*/)
         char lstr[200];
         int zl = 0;
         while (zl < 32 && (zoom >> zl)) zl++;
+        setlocale (LC_NUMERIC, "C");
         sprintf (lstr,
          option == ViewOSMNum ? "%sopenstreetmap.org/?lat=%.5lf&lon=%.5lf&zoom=%d%s" :
          option == EditInPotlatchNum ? "%sopenstreetmap.org/edit?lat=%.5lf&lon=%.5lf&zoom=%d%s" :
@@ -1563,7 +1834,7 @@ int Click (GtkWidget * /*widget*/, GdkEventButton *event, void * /*para*/)
         option = mapMode;
       }
       #else
-      #ifndef _WIN32_WCE
+      #if defined (_WIN32) && !defined (_WIN32_WCE)
       else if (option == UpdateMapNum) {
         struct stat s;
         if (currentBbox[0] == '\0') {
@@ -1591,8 +1862,8 @@ int Click (GtkWidget * /*widget*/, GdkEventButton *event, void * /*para*/)
     }
   }
   else if (option == searchMode) {
-    int row = event->y / SearchSpacing;
-    if (!HandleKeyboard (event) && row < searchCnt && gosmSstr[row]) {
+    int row = y / SearchSpacing;
+    if (!HandleKeyboard (TRUE, x, y) && row < searchCnt && gosmSstr[row]) {
       SetLocation (gosmSway[row]->clon, gosmSway[row]->clat);
       zoom = gosmSway[row]->dlat + gosmSway[row]->dlon + (1 << 15);
       if (zoom <= (1 << 15)) zoom = Style (gosmSway[row])->scaleMax;
@@ -1609,16 +1880,12 @@ int Click (GtkWidget * /*widget*/, GdkEventButton *event, void * /*para*/)
       return RouteTest (NULL /*widget*/, event, NULL /*para*/);
     }
     #endif
-    int perpixel = zoom / w, dx = event->x - w / 2, dy = h / 2 - event->y;
-    if (isDrag) {
-      dx = firstDrag[0] - event->x;
-      dy = event->y - firstDrag[1];
-    }
+    int perpixel = zoom / w, dx = x - w / 2, dy = h / 2 - y;
     int lon = clon + lrint (perpixel *
       (cosAzimuth * (Display3D ? 0 : dx) - sinAzimuth * dy));
     int lat = clat + lrint (perpixel *
       (cosAzimuth * dy + sinAzimuth * (Display3D ? 0 : dx)));
-    if (event->button == 1) {
+    if (button == 1) {
       if (Display3D) {
         double newa = atan2 (sinAzimuth, cosAzimuth) - dx * M_PI / 580;
         cosAzimuth = cos (newa);
@@ -1626,7 +1893,7 @@ int Click (GtkWidget * /*widget*/, GdkEventButton *event, void * /*para*/)
       }
       SetLocation (lon, lat);
 
-      #ifdef NOGTK
+      #ifdef _WIN32
       if (AddWayOrNode && newWays[newWayCnt].cnt < NEWWAY_MAX_COORD) {
         newWays[newWayCnt].coord[newWays[newWayCnt].cnt][0] = clon;
         newWays[newWayCnt].coord[newWays[newWayCnt].cnt++][1] = clat;
@@ -1635,7 +1902,7 @@ int Click (GtkWidget * /*widget*/, GdkEventButton *event, void * /*para*/)
       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (followGPSr), FALSE);
       FollowGPSr = 0;
     }
-    else if (event->button == 2) {
+    else if (button == 2) {
       flon = lon;
       flat = lat;
       GosmFreeRoute ();
@@ -1647,21 +1914,13 @@ int Click (GtkWidget * /*widget*/, GdkEventButton *event, void * /*para*/)
       CallRoute (TRUE, 0, 0);
     }
   }
-  firstDrag[0] = -1;
-  lastRelease = event->time;
-  gtk_widget_queue_clear (draw); 
   return FALSE;
 }
-
-#if 0 //ifdef CHILDREN
-struct childStruct {
-  int minlon, minlat, maxlon, maxlat, z;
-  int pipe[2];
-} child[70];
 #endif
+
 #define STATEINFO OPTIONS o (clat, 0, 0) o (clon, 0, 0) \
  o (sinAzimuth, 0, 0) o (cosAzimuth, 0, 0) o (zoom, 0, 0) o (option, 0, 0) \
- o (draw->allocation.width, 0, 0) o (draw->allocation.height, 0, 0)
+ o (width, 0, 0) o (height, 0, 0)
 #define o(x,min,max) sizeof (x) +
 static const size_t stateSize = STATEINFO 0;
 #undef o
@@ -1693,12 +1952,12 @@ void Draw3DLine (int sx, int sy, int dx, int dy)
   if (Display3D) {
     if (sy < 0) {
       if (dy < 0) return;
-      sx = dx + (dx - sx) * (/*clip.height*/ 1024 - dy) / (dy - sy);
-      sy = /*clip.height*/ 1024;
+      sx = dx + (dx - sx) * (/*height*/ 1024 - dy) / (dy - sy);
+      sy = /*height*/ 1024;
     }
     else if (dy < 0) {
-      dx = sx + (sx - dx) * (/*clip.height*/ 1024 - sy) / (sy - dy);
-      dy = /*clip.height*/ 1024;
+      dx = sx + (sx - dx) * (/*height*/ 1024 - sy) / (sy - dy);
+      dy = /*height*/ 1024;
     }
   }
   gdk_draw_line (draw->window, mygc, sx, sy, dx, dy);
@@ -1721,13 +1980,13 @@ int TestOrSet (int *bits, int set, int x0, int y0, int ax, int ay,
     bx = nx;
     by = ny;
   }
-  if (y0 < 0 || y0 + ay + by > draw->allocation.height ||
-      x0 + ax < 0 || x0 + bx > draw->allocation.width) return TRUE;
+  if (y0 < 0 || y0 + ay + by > height ||
+      x0 + ax < 0 || x0 + bx > width) return TRUE;
   // Do not place anything offscreen.
   const int shf = 9;
   x0 <<= shf;
   int x1 = x0, d0 = (ax << shf) / (ay + 1), d1 = (bx << shf) / (by + 1);
-  int bpr = (draw->allocation.width + 31) / 32;
+  int bpr = (width + 31) / 32;
   bits += bpr * y0;
   for (int cnt = ay + by; cnt > 0; cnt--) {
     x0 += d0;
@@ -1773,20 +2032,20 @@ void ConsiderText (queue<linePtType> *q, int finish, int len, int *best,
     int dx = q->back ().x - q->front ().x, dy = q->back ().y - q->front ().y;
     if (q->size () == 2) { // cumulative can't cope with clipping, so we
                            // only do it when we know detour will be 0
-      for (int i = 0; i < 2; i++) {
-        linePtType *f = !i ? &q->front () : &q->back ();
-        if (f->x < 10 && dx != 0) clip[i] = max (clip[i], 256 * (10 - f->x) / (i ? -dx : dx));
+      LG for (int i = 0; i < 2; i++) {
+        LG linePtType *f = !i ? &q->front () : &q->back ();
+        LG if (f->x < 10 && dx != 0) clip[i] = max (clip[i], 256 * (10 - f->x) / (i ? -dx : dx));
         if (f->y < 10 && dy != 0) clip[i] = max (clip[i], 256 * (10 - f->y) / (i ? -dy : dy));
-        int r2x = f->x - draw->allocation.width + 10;
-        if (r2x > 0 && dx != 0) clip[i] = max (clip[i], 256 * r2x / (i ? dx : -dx));
-        int r2y = f->y - draw->allocation.height + 10;
+        int r2x = f->x - width + 10;
+        LG if (r2x > 0 && dx != 0) clip[i] = max (clip[i], 256 * r2x / (i ? dx : -dx));
+        int r2y = f->y - height + 10;
         if (r2y > 0 && dy != 0) clip[i] = max (clip[i], 256 * r2y / (i ? dy : -dy));
       }
     }
     int dst = isqrt (Sqr (dx) + Sqr (dy)) * (256 - clip[0] - clip[1]) / 256;
     int detour = q->size () == 2 ? 0 : q->back ().cumulative - q->front ().cumulative - dst;
     if (detour <= *best) {
-      if (dst * DetailLevel > len * 14) {
+      LG if (dst * DetailLevel > len * 14) {
         t->x = q->front ().x + dx * clip[0] / 256;
         t->y = q->front ().y + dy * clip[0] / 256;
         t->x2 = q->back ().x - dx * clip[1] / 256;
@@ -1806,14 +2065,168 @@ int WaySizeCmp (ndType **a, ndType **b)
          Way (*b)->dlat * (__int64) Way (*b)->dlon ? 1 : -1;
 }
 
-#ifdef NOGTK
+vector<short> casingCmds;
+#define CASING_MAX 20
+static short casing[10 + CASING_MAX * 2];
+static int casingx, casingy, casingPts = 0;
+void MoveTo (int x, int y)
+{
+#ifdef ANDROID_NDK // OPENGL
+  if (casingPts) {
+    casing[6] = casing[4];
+    casing[7] = casing[5];
+    int i, circ = min ((abs(casing[2] - casing[6]) + abs (casing[3] - casing[7])) / 3, CASING_MAX);
+    for (i = 1; i < circ; i++) {
+      casing[i + i + 6] = casing[6] +
+        (casing[2] - casing[6]) * (1 - cos (i * M_PI / circ))/2 -
+        (casing[3] - casing[7]) * sin (i * M_PI / circ)/2;
+      casing[i + i + 7] = casing[7] +
+        (casing[3] - casing[7]) * (1 - cos (i * M_PI / circ))/2 +
+        (casing[2] - casing[6]) * sin (i * M_PI / circ)/2;
+    }
+    casing[i + i + 6] = casing[2];
+    casing[i + i + 7] = casing[3];
+    glVertexPointer (2, GL_SHORT, 0, casing + 6);
+    casingCmds.push_back (i + 1);
+    casingCmds.push_back (0); // pad
+    casingCmds.insert (casingCmds.end(), casing + 6, casing + 8 + i + i);
+    //if (vol) glDrawArrays (GL_TRIANGLE_FAN, 0, i + 1);
+    glDrawArrays (GL_LINE_STRIP, 0, i + 1);
+  }
+#endif
+  casingx = x;
+  casingy = y;
+  casingPts = 0;
+}
+
+void LineTo (int x, int y, int width)
+{
+#ifdef ANDROID_NDK // OPENGL
+  int d = sqrt (double((x - casingx) * (x - casingx) +
+                       (y - casingy) * (y - casingy))), i;
+  casing[0] = casingx + (Display3D ? (y - casingy) * casingy * width / PIX45
+    : (y - casingy) * width) / (d + d);
+  casing[1] = casingy + (Display3D ? (casingx - x) * casingy * width / PIX45
+    : (casingx - x) * width) / (d + d);
+  casing[6] = casing[0] - (Display3D ? (y - casingy) * casingy * width / PIX45
+    : (y - casingy) * width) / d;
+  casing[7] = casing[1] - (Display3D ? (casingx - x) * casingy * width / PIX45
+    : (casingx - x) * width) / d;
+  if (!casingPts++) {
+    int circ = min ((abs(casing[0] - casing[6]) + abs (casing[1] - casing[7])) / 3, CASING_MAX);
+    for (i = 1; i < circ; i++) {
+      casing[i + i + 6] = casing[6] + 
+        (casing[0] - casing[6]) * (1 - cos (i * M_PI / circ))/2 +
+        (casing[1] - casing[7]) * sin (i * M_PI / circ)/2;
+      casing[i + i + 7] = casing[7] +
+        (casing[1] - casing[7]) * (1 - cos (i * M_PI / circ))/2 -
+        (casing[0] - casing[6]) * sin (i * M_PI / circ)/2;
+    }
+  }
+  else {
+    memcpy (casing + 8, (casing[2] - casingx) * (casingx - x) >
+      (casing[3] - casingy) * (y - casingy) ? casing + 2 : casing + 4, sizeof (casing[2]) * 2);
+    i = 2;
+  }
+  
+  casing[2] = x + (Display3D ? (y - casingy) * y * width / PIX45
+    : (y - casingy) * width) / (d + d);
+  casing[3] = y + (Display3D ? (casingx - x) * y * width / PIX45
+    : (casingx - x) * width) / (d + d);
+  casing[4] = casing[2] - (Display3D ? (y - casingy) * y * width / PIX45
+    : (y - casingy) * width) / d;
+  casing[5] = casing[3] - (Display3D ? (casingx - x) * y * width / PIX45
+    : (casingx - x) * width) / d;
+  glVertexPointer (2, GL_SHORT, 0, casing);
+  casingCmds.push_back (i + 3);
+  casingCmds.push_back (0); // pad
+  casingCmds.insert (casingCmds.end(), casing, casing + i + i + 6);
+  //if (vol) glDrawArrays (GL_TRIANGLE_FAN, 0, i + 3);
+  glDrawArrays (GL_LINE_LOOP, 0, i + 3);  
+#else
+  if (width) {} // Suppress warning from compiler
+  gdk_draw_line (GDK_DRAWABLE (draw->window), mygc, casingx, casingy, x, y);
+#endif
+  casingx = x;
+  casingy = y;
+}
+
+void FinishCasing ()
+{
+  #ifdef ANDROID_NDK // OPENGL
+  MoveTo (0, 0); // Draw round ending for last line
+  glVertexPointer (2, GL_SHORT, 0, &casingCmds[0] + 2);
+  for (int i = 0; i < casingCmds.size ();
+      i += casingCmds[i] < 0 ? 4 : casingCmds[i] + casingCmds[i] + 2) {
+    #ifdef ANDROID_NDK // OPENGL ES
+    if (casingCmds[i] < 0) glColor4x (casingCmds[i + 1] * 0x101,
+           casingCmds[i + 2] * 0x101, casingCmds[i + 3] * 0x101, 0x10000);
+    #else
+    if (casingCmds[i] < 0) glColor3f (casingCmds[i + 1] / 255.0,
+           casingCmds[i + 2] / 255.0, casingCmds[i + 3] / 255.0);
+    #endif
+    else {
+      glVertexPointer (2, GL_SHORT, 0, &casingCmds[i] + 2);
+      glDrawArrays (GL_TRIANGLE_FAN, 0, casingCmds[i]);
+    }
+  }
+  casingCmds.clear();
+  #endif
+}
+
+inline void SetCasingColor (short r, short g, short b)
+{
+  MoveTo (0, 0); // Complete previous line in previous colour
+  casingCmds.push_back (-1);
+  casingCmds.push_back (r); casingCmds.push_back (g); casingCmds.push_back (b);
+}
+
+#if defined (ANDROID_NDK)
+extern "C" void Java_org_osmu_gosmore_MapRenderer_render (
+		JNIEnv*  env, jobject thiz, jdouble lon, jdouble lat,
+		jint dir, jint _zoom, jboolean threeD, jboolean follow,
+		jint _width, jint _height)
+{
+  static int started = 0, icons /* Not used */;
+  LG width = _width;
+  height = _height;
+  Display3D = threeD;
+  clon = Longitude (lon);
+  clat = Latitude (lat);
+  FollowGPSr = follow;
+  sinAzimuth = sin (dir * (M_PI / 180.0));
+  cosAzimuth = cos (dir * (M_PI / 180.0));
+  zoom = _zoom;
+  if (!started) {
+    started = 1;
+    jclass cls=env->GetObjectClass(thiz);
+    //cls =(jclass)( env->NewGlobalRef(jcls) );
+    //cls = env->FindClass(
+    //		  "org/osmu/gosmore/MyClb");
+
+    LG drawTeks = env->GetMethodID(cls, "drawTeks", "(Ljava/lang/String;IIFF)V");
+    // env->ExceptionClear();
+    /* if (drawTeksod != 0)*/
+    // env->ExceptionClear();
+  }
+  glDisable(GL_BLEND);
+  if (currentBbox[0] != '\0' && hashTable[bucketsMin1] < 500000 &&
+      zoom < 100000000) {
+    int nn = clat > -(1<<24) && clat < (1<<24) &&
+             clon > -(1<<24) && clon < (1<<24);
+    jstring js = env->NewStringUTF (nn ? "No location." : "No map.");
+    env->CallVoidMethod (thiz, drawTeks, js, width / 2, height/3*2,
+      (float)0, (float)1);
+    js = env->NewStringUTF (nn ? "Please search or enable the GPS" :
+      "Please update the map.");
+    env->CallVoidMethod (thiz, drawTeks, js, width / 2, height/3*2 + 30,
+      (float)0, (float)1);
+  }
+#elif defined(NOGTK)
 int DrawExpose (HPEN *pen, HBRUSH *brush)
 {
-  struct {
-    int width, height;
-  } clip;
-/*  clip.width = GetSystemMetrics(SM_CXSCREEN);
-  clip.height = GetSystemMetrics(SM_CYSCREEN); */
+  width = draw->allocation.width;
+  height = draw->allocation.height;
   WCHAR wcTmp[70];
 
   iconsgc = mygc;
@@ -1824,18 +2237,18 @@ int DrawExpose (HPEN *pen, HBRUSH *brush)
     SelectObject (mygc, sysFont);
     //SetBkMode (mygc, TRANSPARENT);
     SelectObject (mygc, GetStockObject (BLACK_PEN));
-    for (int y = 0, i = objectAddRow; y < draw->allocation.height;
+    for (int y = 0, i = objectAddRow; y < height;
               y += ADD_HEIGHT) {
-      //gdk_draw_line (draw->window, mygc, 0, y, draw->allocation.width, y);
+      //gdk_draw_line (draw->window, mygc, 0, y, width, y);
       gdk_draw_line (draw->window, mygc,
-        draw->allocation.width - ButtonSize * 20,
-        draw->allocation.height * i / restriction_no_right_turn,
-        draw->allocation.width,
-        draw->allocation.height * i / restriction_no_right_turn);
+        width - ButtonSize * 20,
+        height * i / restriction_no_right_turn,
+        width,
+        height * i / restriction_no_right_turn);
       RECT klip;
       klip.bottom = y + ADD_HEIGHT;
       klip.top = y;
-      for (int x = 0; x < draw->allocation.width - ButtonSize * 20 -
+      for (int x = 0; x < width - ButtonSize * 20 -
           ADD_WIDTH && i < restriction_no_right_turn; x += ADD_WIDTH, i++) {
         int *icon = style[i].x + 4 * IconSet;
         gdk_draw_drawable (draw->window, mygc, icons, icon[0], icon[1],
@@ -1867,6 +2280,8 @@ gint DrawExpose (void)
 {
   static GdkColor styleColour[2 << STYLE_BITS][2];
   static GdkColor /*routeColour, validateColour,*/ resultArrowColour;
+  height = draw->allocation.height;
+  width = draw->allocation.width;
   if (!mygc || !iconsgc) {
     mygc = gdk_gc_new (draw->window);
     fg_gc = gdk_gc_new (draw->window);
@@ -1898,41 +2313,14 @@ gint DrawExpose (void)
               firstElemStyle + Background - (Background > 8 ? 8 : 0)][0]);
     oldBackground = Background;
   }
-  #if 0 //ifdef CHILDREN
-  if (1) {
-    vector<char> msg;
-    msg.resize (4 + 3 * sizeof (XID), 0); // Zero the header
-    *(XID*)&msg[4] = GDK_WINDOW_XID (draw->window);
-    *(XID*)&msg[4 + sizeof (XID)] = GDK_PIXMAP_XID (icons);
-    *(XID*)&msg[4 + sizeof (XID) * 2] = GDK_PIXMAP_XID (mask);
-    #define o(x,min,max) msg.resize (msg.size () + sizeof (x)); \
-                    memcpy (&msg[msg.size () - sizeof (x)], &x, sizeof (x));
-    STATEINFO
-    #undef o
-    write (child[0].pipe[1], &msg[0], msg.size ());
-    // Avoid flicker here : gtk_widget_set_double_buffered
-    //sleep (1);
-    read (child[0].pipe[0], &msg[0], 4);
-    /* Wait for finish to prevent queuing too many requests */
-    return FALSE;
-  }
-  #endif
   GdkRectangle r =
-    { 0, 0, draw->allocation.width, draw->allocation.height };
+    { 0, 0, width, height };
   gdk_window_begin_paint_rect (draw->window, &r);
 
-//  gdk_gc_set_clip_rectangle (mygc, &clip);
 //  gdk_gc_set_foreground (mygc, &styleColour[0][0]);
 //  gdk_gc_set_line_attributes (mygc,
 //    1, GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
     
-//  clip.width = draw->allocation.width - ZOOM_PAD_SIZE;
-//  gdk_gc_set_clip_rectangle (mygc, &clip);
-  
-  GdkRectangle clip;
-  clip.x = 0;
-  clip.y = 0;
-
   PangoMatrix mat = PANGO_MATRIX_INIT;
   pc = gdk_pango_context_get_for_screen (gdk_screen_get_default ());
   pl = pango_layout_new (pc);
@@ -1950,73 +2338,35 @@ gint DrawExpose (void)
     pango_layout_set_attributes (pl, list);
     pango_attr_list_unref (list); */
 #endif // GTK
-  if (option == mapMode) ChangePak (NULL, clon, clat);
+  LG if (option == mapMode) ChangePak (NULL, clon, clat);
   // This call can be almost anywhere, e.g. SetLocation(). Calling it in
   // searchMode with GeoSearch may invalidate some of the results.
 
-  clip.height = draw->allocation.height;
-  clip.width = draw->allocation.width;
-  
   if (ButtonSize <= 0) ButtonSize = 4;
 
   if (zoom < 0 || zoom > 1023456789) zoom = 1023456789;
-  if (zoom / clip.width <= 1) zoom += 4000;
-  int cosa = lrint (4294967296.0 * cosAzimuth * clip.width / zoom);
-  int sina = lrint (4294967296.0 * sinAzimuth * clip.width / zoom);
-  int xadj =
-    clip.width / 2 - ((clon * (__int64) cosa + clat * (__int64) sina) >> 32);
-  __int64 yadj =
-    clip.height / 2 - ((clon * (__int64) sina - clat * (__int64) cosa) >> 32);
-
-  #define FAR3D  100000 // 3D view has a limit of roughly 5 km forwards 
-  #define WIDE3D 100000 // and roughly 5km between top left & top right corner
-  #define CAMERA2C 20000 // How far the camera is behind the user (clat/lon)
-  #define HEIGHT   12000 // Height of the camera
-  #define PIX45     256 // Y value corresponding to 45 degrees down
-  #define XFix PIX45
-  
-  #define MUL 64
-  if (Display3D) {
+  if (zoom / width <= 1) zoom += 4000;
+
+  LG cosa = lrint (4294967296.0 * cosAzimuth * width / zoom);
+  sina = lrint (4294967296.0 * sinAzimuth * width / zoom);
+  xadj =
+    width / 2 - ((clon * (__int64) cosa + clat * (__int64) sina) >> 32);
+  yadj =
+    height / 2 - ((clon * (__int64) sina - clat * (__int64) cosa) >> 32);
+
+  LG if (Display3D) {
     cosa = lrint (cosAzimuth * MUL);
     sina = lrint (sinAzimuth * MUL);
-    
-    #define myint int
-    /* The 3D computations can all be done in signed 32 bits integers,
-       provided overflow bits are simply discarded. The C specification says
-       however that ints that overflow are undefined (as well as any
-       expression that touches them). So if the 3D display looks garbled
-       under a new compiler, try running with #define myint __int64
-    */
-    
+
     yadj = (clon + (int)(sinAzimuth * CAMERA2C)) * (myint) sina -
            (clat - (int)(cosAzimuth * CAMERA2C)) * (myint) cosa;
     xadj = -(clon + (int)(sinAzimuth * CAMERA2C)) * (myint) cosa -
             (clat - (int)(cosAzimuth * CAMERA2C)) * (myint) sina;
   }
-  #define Depth(lon,lat) \
-    (int)(yadj + (lat) * (myint) cosa - (lon) * (myint) sina)
-  #define X1(lon,lat) \
-    (int)(xadj + (lon) * (myint) cosa + (lat) * (myint) sina)
-  #define AdjDepth(lon,lat) (Depth (lon, lat) < PIX45 * HEIGHT * MUL / 5000 \
-    && Depth (lon, lat) > -PIX45 * HEIGHT * MUL / 5000 ? \
-    PIX45 * HEIGHT * MUL / 5000 : Depth (lon, lat))
-  #define Y(lon,lat) (Display3D ? PIX45 * HEIGHT * MUL / AdjDepth (lon, lat) \
-  : yadj + (int)(((lon) * (__int64) sina - (lat) * (__int64) cosa) >> 32))
-  #define X(lon,lat) (Display3D ? clip.width / 2 + \
-   ((AdjDepth (lon, lat) > 0 ? 1 : -1) * \
-      (X1 (lon, lat) / 32000 - AdjDepth (lon, lat) / XFix) > 0 ? 32000 : \
-    (AdjDepth (lon, lat) > 0 ? 1 : -1) * \
-      (X1 (lon, lat) / 32000 + AdjDepth (lon, lat) / XFix) < 0 ? -32000 : \
-   X1(lon,lat) / (AdjDepth (lon, lat) / XFix)) \
-  : xadj + (int)(((lon) * (__int64) cosa + (lat) * (__int64) sina) >> 32))
-
-  /* These macros calling macros may result in very long bloated code and
-     inefficient machine code, depending on how well the compiler optimizes.
-  */
 
   if (option == mapMode) {
-//    int perpixel = zoom / clip.width;
-    int *block = (int*) calloc ((clip.width + 31) / 32 * 4, clip.height);
+//    int perpixel = zoom / width;
+    int *block = (int*) calloc ((width + 31) / 32 * 4, height);
 
     stack<text2Brendered> text2B;
     text2B.push (text2Brendered ()); // Always have a spare one open
@@ -2028,11 +2378,11 @@ gint DrawExpose (void)
       for (int i = 0; i < 2; i++) {
         for (int m = -20; m <= 20; m += 40) {
           text2B.top ().s = m < 0 ? (i ? "N" : "W") : i ? "S" : "E";
-          text2B.top ().x = clip.width - 40 +
+          text2B.top ().x = width - 40 +
             lrint ((i ? -sinAzimuth : cosAzimuth) * m) - 50;
           text2B.top ().x2 = text2B.top ().x + 100;
           text2B.top ().dst = 100;
-          text2B.top ().y2 = text2B.top ().y = clip.height - 40 +
+          text2B.top ().y2 = text2B.top ().y = height - 40 +
             lrint ((i ? cosAzimuth : sinAzimuth) * m);
           text2B.push (text2Brendered ());
         }
@@ -2050,7 +2400,7 @@ gint DrawExpose (void)
     for (int wc = -1; wc <= 1; wc += 2) { // width and
       for (int hc = -1; hc <= 1; hc += 2) { // height coefficients
         int w = !Display3D ? zoom : hc > 0 ? WIDE3D : 0, h = !Display3D
-          ? zoom / clip.width * clip.height : hc > 0 ? FAR3D : CAMERA2C;
+          ? zoom / width * height : hc > 0 ? FAR3D : CAMERA2C;
         int lon = lrint (w * cosAzimuth * wc - h * sinAzimuth * hc);
         int lat = lrint (h * cosAzimuth * hc + w * sinAzimuth * wc);
         lonRadius[0] = min (lonRadius[0], lon);
@@ -2059,16 +2409,16 @@ gint DrawExpose (void)
         latRadius[1] = max (latRadius[1], lat);
       }
     }
-    OsmItr itr (clon + lonRadius[0] - 1000, clat + latRadius[0] - 1000,
+    LG OsmItr itr (clon + lonRadius[0] - 1000, clat + latRadius[0] - 1000,
                 clon + lonRadius[1] + 1000, clat + latRadius[1] + 1000);
     // Widen this a bit so that we render nodes that are just a bit offscreen ?
     while (Next (itr)) {
       ndType *nd = itr.nd[0];
       wayType *w = Way (nd);
 
-      if (Style (w)->scaleMax < zoom / clip.width * 350 / (DetailLevel + 6)
-          && !Display3D && w->dlat < zoom / clip.width * 20 &&
-                           w->dlon < zoom / clip.width * 20) continue;
+      if (Style (w)->scaleMax < zoom / width * 350 / (DetailLevel + 6)
+          && !Display3D && w->dlat < zoom / width * 20 &&
+                           w->dlon < zoom / width * 20) continue;
       // With 3D, the icons are filtered only much later when we know z.
       if (nd->other[0] != 0) {
         nd = itr.nd[0] + itr.nd[0]->other[0];
@@ -2078,45 +2428,52 @@ gint DrawExpose (void)
       } // Only process this way when the Itr gives us the first node, or
       // the first node that's inside the viewing area
       if (nd->other[0] == 0 && nd->other[1] == 0) dlist[11].push (nd);
-      else if (Style (w)->areaColour != -1) area.push_back (nd);
+      else if (Style (w)->areaColour != -1 ||
+        StyleNr(w) == natural_coastline) area.push_back (nd);
+      // I guess polygons that enter the bbox multiple times are drawn
+      // multiple times.
       else dlist[Layer (w) + 5].push (nd);
     }
-    qsort (&area[0], area.size (), sizeof (area[0]),
+    LG qsort (&area[0], area.size (), sizeof (area[0]),
       (int (*)(const void *a, const void *b))WaySizeCmp);
     //for (; !dlist[0].empty (); dlist[0].pop ()) {
     //  ndType *nd = dlist[0].top ();
+    vector<PolygonEdge> coast;
+    vector<FixedPoint*> cpiece;
     for (; !area.empty(); area.pop_back ()) {
       ndType *nd = area.back ();
       wayType *w = Way (nd);
-      while (nd->other[0] != 0) nd += nd->other[0];
-      #if defined (_WIN32_CE) || defined (NOGTK)
+      if (StyleNr(w) != natural_coastline) {
+        while (nd->other[0] != 0) nd += nd->other[0];
+      }
+      #if defined (_WIN32_CE) || defined (_WIN32)
       #define GdkPoint POINT
       #endif
-      vector<GdkPoint> pt;
+      vector<FixedPoint> pt;
       int oldx = 0, oldy = 0, x = 0 /* Shut up gcc*/, y = 0 /*Shut up gcc*/;
       int firstx = INT_MIN, firsty = INT_MIN /* Shut up gcc */;
-      for (; nd->other[1] != 0; nd += nd->other[1]) {
+      for (; ; nd += nd->other[1]) {
         if (nd->lat != INT_MIN) {
-          pt.push_back (GdkPoint ());
-          pt.back ().x = x = X (nd->lon, nd->lat);
-          pt.back ().y = y = Y (nd->lon, nd->lat);
+          pt.push_back (FixedPoint ());
+          pt.back ().x = x = X2 (nd->lon, nd->lat);
+          pt.back ().y = y = Y2 (nd->lon, nd->lat);
           if (Display3D) {
             if (firstx == INT_MIN) {
               firstx = x;
               firsty = y;
             }
             if (y > 0 && oldy < 0) {
-              pt.back ().x = x + (x - oldx) * (1024 - y) / (y - oldy);
-              pt.back ().y = 1024; // Insert modified instance of old point
-              pt.push_back (GdkPoint ());
+              pt.back ().x = x + (x - oldx) * __int64((1<<26) - y) / (y - oldy);
+              pt.back ().y = 1<<26; // Insert modified instance of old point
+              pt.push_back (FixedPoint ());
               pt.back ().x = x; // before current point.
               pt.back ().y = y;
             }
             else if (y < 0) {
               if (oldy < 0) pt.pop_back ();
               else {
-                pt.back ().x = oldx + (oldx - x) * (1024 - oldy) / (oldy - y);
-                pt.back ().y = 1024;
+                pt.back ().x = oldx + (oldx - x) * __int64((1<<26) - oldy) / (oldy - y);
+                pt.back ().y = 1<<26;
               }
             }
             oldx = x;
@@ -2125,67 +2482,119 @@ gint DrawExpose (void)
           //pt[pts].x = X (nd->lon, nd->lat);
           //pt[pts++].y = Y (nd->lon, nd->lat);
         }
+        if (!nd->other[1]) break;
       }
       
       if (Display3D && y < 0 && firsty > 0) {
-        pt.push_back (GdkPoint ());
-        pt.back ().x = firstx + (firstx - x) * (1024 - firsty) / (firsty - y);
-        pt.back ().y = 1024;
+        pt.push_back (FixedPoint ());
+        pt.back ().x = firstx + (firstx - x) * __int64((1<<26) - firsty) / (firsty - y);
+        pt.back ().y = 1<<26;
       }
       if (Display3D && firsty < 0 && y > 0) {
-        pt.push_back (GdkPoint ());
-        pt.back ().x = x + (x - firstx) * (1024 - y) / (y - firsty);
-        pt.back ().y = 1024;
+        pt.push_back (FixedPoint ());
+        pt.back ().x = x + (x - firstx) * __int64((1<<26) - y) / (y - firsty);
+        pt.back ().y = 1<<26;
       }
       if (!pt.empty ()) {
-        #ifdef NOGTK
-        SelectObject (mygc, brush[StyleNr (w)]);
-        SelectObject (mygc, pen[StyleNr (w)]);
-        Polygon (mygc, &pt[0], pt.size ());
+        #if defined(ANDROID_NDK) || !defined(NOGTK)
+        if (StyleNr(w) == natural_coastline) {
+          cpiece.push_back ((FixedPoint*) malloc (pt.size() * sizeof (FixedPoint)));
+          memcpy (cpiece.back(), &pt[0], pt.size() * sizeof (FixedPoint));
+          AddClockwise (coast, cpiece.back(), pt.size());
+        }
+        else {
+          vector<PolygonEdge> pe;
+          AddPolygon (pe, &pt[0], pt.size ());
+          #ifdef ANDROID_NDK
+          #define glSColor(x) glColor4x ((x) >> 8, (x) & 0xffff, \
+                              ((x) << 8)&0xffff, 0x10000)
+          glSColor (Style(w)->areaColour);
+          Fill (pe,FALSE); 
+          #else
+          gdk_gc_set_foreground (mygc, &styleColour[Style (w) - style][0]);
+          Fill (pe, FALSE, draw->window, mygc);
+          #endif
+          /*if (pt.size () < 10) {
+            vector<PolygonEdge> pe2;
+            AddPolygon (pe2, &pt[0], pt.size ());
+            Fill (pe2,draw->window,mygc);
+          }*/
+             /*if (!Fill (pe)) {
+            __android_log_print (ANDROID_LOG_WARN, "Gosmore", "s %d", pt.size());
+            for (int m = 0; m < pt.size (); m++)
+              __android_log_print (ANDROID_LOG_WARN, "Gosmore", "%d %d", pt[m].x, pt[m].y);
+          }*/
+          // TODO: border
+          //glSColor ((Style(w)->areaColour >> 1) & 0xefefef);
+          //glLineWidth(1);
+        #elif defined(NOGTK)
+        if (StyleNr(w) != natural_coastline) {
+          SelectObject (mygc, brush[StyleNr (w)]);
+          SelectObject (mygc, pen[StyleNr (w)]);
+          Polygon (mygc, &pt[0], pt.size ());
         #else
-        gdk_gc_set_foreground (mygc, &styleColour[Style (w) - style][0]);
-        gdk_draw_polygon (draw->window, mygc, TRUE, &pt[0], pt.size ());
-        gdk_gc_set_foreground (mygc, &styleColour[Style (w) - style][1]);
-        gdk_gc_set_line_attributes (mygc, Style (w)->lineWidth,
-          Style (w)->dashed ? GDK_LINE_ON_OFF_DASH
-          : GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
-        gdk_draw_polygon (draw->window, mygc, FALSE, &pt[0], pt.size ());
+        if (StyleNr(w) != natural_coastline) {
+          gdk_gc_set_foreground (mygc, &styleColour[Style (w) - style][0]);
+          gdk_draw_polygon (draw->window, mygc, TRUE, &pt[0], pt.size ());
+          gdk_gc_set_foreground (mygc, &styleColour[Style (w) - style][1]);
+          gdk_gc_set_line_attributes (mygc, Style (w)->lineWidth,
+            Style (w)->dashed ? GDK_LINE_ON_OFF_DASH
+            : GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
+          gdk_draw_polygon (draw->window, mygc, FALSE, &pt[0], pt.size ());
         #endif
-        // Text placement: The basic idea is here : http://alienryderflex.com/polygon_fill/
-        text2B.top ().dst = strcspn ((char*)(w + 1) + 1, "\n") * 9;
-        text2B.top ().x = -1;
-        for (unsigned i = 0; i < pt.size (); i++) {
-          int iy = (pt[i].y + pt[i < pt.size () - 1 ? i + 1 : 0].y) / 2;
-          // Look for a large horisontal space inside the poly at this y value
-          vector<int> nx;
-          for (unsigned j = 0, k = pt.size () - 1; j < pt.size (); j++) {
-            if ((pt[j].y < iy && pt[k].y >= iy) || (pt[k].y < iy && pt[j].y >= iy)) {
-              nx.push_back (pt[j].x + (pt[k].x - pt[j].x) * (iy - pt[j].y) /
-                (pt[k].y - pt[j].y));
-            }
-            k = j;
+          // Text placement: The basic idea is here : http://alienryderflex.com/polygon_fill/
+          text2B.top ().dst = strcspn ((char*)(w + 1) + 1, "\n") * 9;
+          text2B.top ().x = -1;
+          for (unsigned i = 0; i < pt.size (); i++) {
+            pt[i].x >>= 16;
+            pt[i].y >>= 16;
           }
-          sort (nx.begin (), nx.end ());
-          for (unsigned int j = 0; j < nx.size (); j += 2) {
-            if (nx[j + 1] - nx[j] > text2B.top ().dst) {
-              text2B.top ().x = nx[j];
-              text2B.top ().x2 = nx[j + 1];
-              text2B.top ().y = iy - 5;
-              text2B.top ().dst = nx[j + 1] - nx[j];
+          for (unsigned i = 0; i < pt.size (); i++) {
+            int iy = (pt[i].y + pt[i < pt.size () - 1 ? i + 1 : 0].y) / 2;
+            // Look for a large horisontal space inside the poly at this y value
+            vector<int> nx;
+            for (unsigned j = 0, k = pt.size () - 1; j < pt.size (); j++) {
+              if ((pt[j].y < iy && pt[k].y >= iy) || (pt[k].y < iy && pt[j].y >= iy)) {
+                nx.push_back (pt[j].x + (pt[k].x - pt[j].x) * (iy - pt[j].y) /
+                  (pt[k].y - pt[j].y));
+              }
+              k = j;
+            }
+            sort (nx.begin (), nx.end ());
+            for (unsigned int j = 0; j < nx.size (); j += 2) {
+              if (nx[j + 1] - nx[j] > text2B.top ().dst) {
+                text2B.top ().x = nx[j];
+                text2B.top ().x2 = nx[j + 1];
+                text2B.top ().y = iy - 5;
+                text2B.top ().dst = nx[j + 1] - nx[j];
+              }
             }
           }
-        }
-        if (text2B.top ().x >= 0) {
-          text2B.top ().y2 = text2B.top ().y;
-          text2B.top ().s = (char*)(w + 1) + 1;
-          text2B.push (text2Brendered ());
-        }
+          if (text2B.top ().x >= 0) {
+            text2B.top ().y2 = text2B.top ().y;
+            text2B.top ().s = (char*)(w + 1) + 1;
+            text2B.push (text2Brendered ());
+          }
+        } // If not a coastline
       } // Polygon not empty
     } // For each area
+    #ifdef ANDROID_NDK
+    glColor4x (0x8000, 0x8000, 0x10000, 0x10000);
+    LG Fill (coast, TRUE);
+    for (; cpiece.size () > 0; cpiece.pop_back()) free (cpiece.back());
+    glLineWidth (2);
+    #elif !defined (NOGTK)
+    gdk_gc_set_foreground (mygc, &styleColour[natural_coastline][1]);
+    Fill (coast, TRUE, draw->window,mygc);
+    for (; cpiece.size () > 0; cpiece.pop_back()) free (cpiece.back());
+    #endif
 
-    queue<linePtType> q;
-    for (int l = 0; l < 12; l++) {
-      for (; !dlist[l].empty (); dlist[l].pop ()) {
+    LG queue<linePtType> q;
+    LG for (int l = 0; l < 12; l++) {
+      #ifdef ANDROID_NDK
+      glColor4x (0, 0, 0, 0x10000);
+      #endif
+      LG for (; !dlist[l].empty (); dlist[l].pop ()) {
         ndType *nd = dlist[l].top ();
         wayType *w = Way (nd);
 
@@ -2193,13 +2602,13 @@ gint DrawExpose (void)
         int len = strcspn ((char *)(w + 1) + 1, "\n");
         
 	// single-point node
-        if (nd->other[0] == 0 && nd->other[1] == 0) {
+        LG if (nd->other[0] == 0 && nd->other[1] == 0) {
           int x = X (nd->lon, nd->lat), y = Y (nd->lon, nd->lat);
           int *icon = Style (w)->x + 4 * IconSet, wd = icon[2], ht = icon[3];
           if ((!Display3D || y > Style (w)->scaleMax / 400) && !TestOrSet (
                       block, FALSE, x - wd / 2, y - ht / 2, 0, ht, wd, 0)) {
             TestOrSet (block, TRUE, x - wd / 2, y - ht / 2, 0, ht, wd, 0);
-            DrawPoI (x, y, Style (w)->x + 4 * IconSet);
+            LG DrawPoI (x, y, Style (w)->x + 4 * IconSet);
             
             #if 0 //def NOGTK
             SelectObject (mygc, sysFont);
@@ -2219,7 +2628,7 @@ gint DrawExpose (void)
             text2B.top ().y2 = text2B.top ().y = y +
                                Style (w)->x[IconSet * 4 + 3] / 2;
             if (Sqr ((__int64) Style (w)->scaleMax / 2 /
-                (zoom / clip.width)) * DetailLevel > len * len * 100 &&
+                (zoom / width)) * DetailLevel > len * len * 100 &&
                 len > 0) best = 0;
           }
         }
@@ -2227,7 +2636,7 @@ gint DrawExpose (void)
         else if (nd->other[1] != 0) {
 	  // perform validation (on non-areas)
 	  bool valid;
-	  if (ValidateMode && Style(w)->areaColour == -1) {
+	  LG if (ValidateMode && Style(w)->areaColour == -1) {
 	    valid = len > 0 && StyleNr (w) != highway_road;
 	    // most ways should have labels and they should not be
 	    // highway=road
@@ -2250,10 +2659,13 @@ gint DrawExpose (void)
           }
 	  // two stages -> validate (if needed) then normal rendering
 	  ndType *orig = nd;
-	  for (int stage = ( valid ? 1 : 0);stage<2;stage++) {
+	  LG for (int stage = ( valid ? 1 : 0);stage<2;stage++) {
 	    nd = orig;
 	    if (stage==0) {
-            #ifndef NOGTK
+            #ifdef ANDROID_NDK
+	    	glColor4x (0x10000, 0x999A, 0x999A, 0x1000);
+	    	glLineWidth(10);
+            #elif !defined(NOGTK)
 	      gdk_gc_set_foreground (mygc,
 	        &styleColour[firstElemStyle + ValidateModeNum][1]); //&validateColour);
 	      gdk_gc_set_line_attributes (mygc, 10,
@@ -2264,7 +2676,12 @@ gint DrawExpose (void)
             #endif
 	    }
 	    else if (stage == 1) {
-              #ifndef NOGTK
+              #ifdef ANDROID_NDK
+	      //glSColor (Style(w)->lineColour);
+              //glLineWidth(Style(w)->lineWidth);
+              SetCasingColor (Style(w)->lineColour >> 16,
+                (Style(w)->lineColour>>8)&0xff, Style(w)->lineColour & 0xff);
+              #elif !defined(NOGTK)
 	      gdk_gc_set_foreground (mygc, &styleColour[Style (w) - style][1]);
 	      gdk_gc_set_line_attributes (mygc, Style (w)->lineWidth,
 		    Style (w)->dashed ? GDK_LINE_ON_OFF_DASH
@@ -2275,17 +2692,18 @@ gint DrawExpose (void)
 	    }
 	    int oldx = X (nd->lon, nd->lat), oldy = Y (nd->lon, nd->lat);
 	    int cumulative = 0;
-            q.push (linePtType (oldx, oldy, cumulative));
+            LG q.push (linePtType (oldx, oldy, cumulative));
+            MoveTo (oldx, oldy);
 	    do {
 	      ndType *next = nd + nd->other[1];
-	      if (next->lat == INT_MIN) break; // Node excluded from build
-	      int x = X (next->lon, next->lat), x2;
+	      LG if (next->lat == INT_MIN) break; // Node excluded from build
+	      LG int x = X (next->lon, next->lat), x2;
 	      int y = Y (next->lon, next->lat), y2;
 //	      printf ("%6.0lf %6.0lf - %6.0lf %6.0lf - %lf\n", x, y, oldx, oldy,
 //	        AdjDepth (next->lon, next->lat));
-	      if ((x <= clip.width || oldx <= clip.width) &&
+	      if ((x <= width || oldx <= width) &&
 		  (x >= 0 || oldx >= 0) && (y >= 0 || oldy >= 0) &&
-		  (y <= clip.height || oldy <= clip.height)) {
+		  (y <= height || oldy <= height)) {
 //                printf ("%4d %4d - %4d %4d\n", x,y,oldx,oldy);
                 /* If we're doing 3D and oldy is negative, it means the point
                    was behind the camera. Then we must draw an infinitely long
@@ -2301,9 +2719,10 @@ gint DrawExpose (void)
                  /*   if (nx < 32760 && nx > -32760 &&
                       oldx < 32760 && oldx > -32760 &&
                       oldy < 32760 && oldy > -32760) */
-                    oldx = x + (x - oldx) * (clip.height + 10 - y) /
+                    oldx = x + (x - oldx) * (height + 10 - y) /
                       (y - oldy);
-                    oldy = clip.height + 10;
+                    oldy = height + 10;
+                    MoveTo (oldx, oldy);
                   }
                 }
                 else /*if (oldy > 0 which is true)*/ {
@@ -2311,50 +2730,61 @@ gint DrawExpose (void)
                     oldx < 32760 && oldx > -32760 &&
                     oldy < 32760 && oldy > -32760) */
                   x2 = oldx +
-                    (oldx - x) * (clip.height + 10 - oldy) / (oldy - y);
-                  y2 = clip.height + 10;
+                    (oldx - x) * (height + 10 - oldy) / (oldy - y);
+                  y2 = height + 10;
                 }
-                gdk_draw_line (draw->window, mygc, oldx, oldy, x2, y2);
+                #ifdef ANDROID_NDK
+                LineTo (x2, y2, Style(w)->lineWidth *
+                  max (width * 1000 / zoom, 2));
+                #else
+                LG gdk_draw_line (draw->window, mygc, oldx, oldy, x2, y2);
+                #endif
                 // Draw3DLine
-                if (oldx < 0 || oldx >= clip.width ||
-                    oldy < 0 || oldy >= clip.height) {
+                LG if (oldx < 0 || oldx >= width ||
+                    oldy < 0 || oldy >= height) {
                   cumulative += 9999; // Insert a break in the queue
-                  q.push (linePtType (oldx, oldy, cumulative));
+                  LG q.push (linePtType (oldx, oldy, cumulative));
                   // TODO: Interpolate the segment to get a point that is
                   // closer to the screen. The same applies to the other push
                 }
-                cumulative += isqrt (Sqr (oldx - x2) + Sqr (oldy - y2));
-                q.push (linePtType (x2, y2, cumulative));
-                ConsiderText (&q, FALSE, len, &best, &text2B.top ());
+                LG cumulative += isqrt (Sqr (oldx - x2) + Sqr (oldy - y2));
+                LG q.push (linePtType (x2, y2, cumulative));
+                LG ConsiderText (&q, FALSE, len, &best, &text2B.top ());
 	      }
-	      nd = next;
+	      else MoveTo (x, y);
+	      LG nd = next;
 	      oldx = x;
 	      oldy = y;
 	    } while (itr.left <= nd->lon && nd->lon < itr.right &&
 		     itr.top  <= nd->lat && nd->lat < itr.bottom &&
 		     nd->other[1] != 0);
-            ConsiderText (&q, TRUE, len, &best, &text2B.top ());
+            LG ConsiderText (&q, TRUE, len, &best, &text2B.top ());
 	  }
 	} /* If it has one or more segments */
 	  
-        if (best < 30) {
+        LG if (best < 30) {
           text2B.top ().s = (char *)(w + 1) + 1;
           text2B.push (text2Brendered ());
         }
       } /* for each way / icon */
+      FinishCasing();
     } // For each layer
   //  gdk_gc_set_foreground (draw->style->fg_gc[0], &highwayColour[rail]);
   //  gdk_gc_set_line_attributes (draw->style->fg_gc[0],
   //    1, GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
 
     // render route
-    routeNodeType *rt;
+    LG routeNodeType *rt;
     if (shortest && (rt = shortest->shortest)) {
       double len;
       int nodeCnt = 1, x = X (rt->nd->lon, rt->nd->lat);
       int y = Y (rt->nd->lon, rt->nd->lat);
       __int64 sumLat = rt->nd->lat;
-      #ifndef NOGTK
+      #ifdef ANDROID_NDK
+      glSColor (style[firstElemStyle + StartRouteNum].lineColour);
+      glLineWidth (6);
+      #define CHARWIDTH 12
+      #elif !defined(NOGTK)
       gdk_gc_set_foreground (mygc,
         &styleColour[firstElemStyle + StartRouteNum][1]); //routeColour);
       gdk_gc_set_line_attributes (mygc, 6,
@@ -2371,8 +2801,8 @@ gint DrawExpose (void)
       for (; rt->shortest; rt = rt->shortest) {
         int nx = X (rt->shortest->nd->lon, rt->shortest->nd->lat);
         int ny = Y (rt->shortest->nd->lon, rt->shortest->nd->lat);
-        if ((nx >= 0 || x >= 0) && (nx < clip.width || x < clip.width) &&
-            (ny >= 0 || y >= 0) && (ny < clip.height || y < clip.height)) {
+        if ((nx >= 0 || x >= 0) && (nx < width || x < width) &&
+            (ny >= 0 || y >= 0) && (ny < height || y < height)) {
           // Gdk looks only at the lower 16 bits ?
           Draw3DLine (x, y, nx, ny);
         }
@@ -2389,32 +2819,38 @@ gint DrawExpose (void)
       char distStr[13];
       sprintf (distStr, "%.3lf km", len * (20000 / 2147483648.0) *
         cos (LatInverse (sumLat / nodeCnt) * (M_PI / 180)));
-      DrawString (clip.width - CHARWIDTH * strlen (distStr), 10, distStr);
+      #ifdef ANDROID_NDK
+      jstring js = env->NewStringUTF (distStr);
+      env->CallVoidMethod (thiz, drawTeks, js, width -
+        CHARWIDTH/2 * strlen (distStr), 40, (float)0, (float)1);
+      #else
+      DrawString (width - CHARWIDTH * strlen (distStr), 10, distStr);
+      #endif
       #if 0 //ndef NOGTK
       gdk_draw_string (draw->window, f, fg_gc, //draw->style->fg_gc[0],
-        clip.width - 7 * strlen (distStr), 10, distStr);
+        width - 7 * strlen (distStr), 10, distStr);
       #else
       #endif
     }
-    DrawPoI (X (flon, flat), Y (flon, flat), IconSet * 4 +
+    LG DrawPoI (X (flon, flat), Y (flon, flat), IconSet * 4 +
       style[firstElemStyle + StartRouteNum].x);
-    DrawPoI (X (tlon, tlat), Y (tlon, tlat), IconSet * 4 +
+    LG DrawPoI (X (tlon, tlat), Y (tlon, tlat), IconSet * 4 +
       style[firstElemStyle + EndRouteNum].x);
     #ifndef NOGTK
-    for (deque<wayPointStruct>::iterator w = wayPoint.begin ();
+    LG for (deque<wayPointStruct>::iterator w = wayPoint.begin ();
          w != wayPoint.end (); w++) {
       DrawPoI (X (w->lon, w->lat), Y (w->lon, w->lat),
         style[firstElemStyle + wayPointIconNum].x);
     }
     
-    for (int i = 1; shortest && ShowActiveRouteNodes && i < routeHeapSize; i++) {
+    LG for (int i = 1; shortest && ShowActiveRouteNodes && i < routeHeapSize; i++) {
       gdk_draw_line (draw->window, mygc,
         X (routeHeap[i].r->nd->lon, routeHeap[i].r->nd->lat) - 2,
         Y (routeHeap[i].r->nd->lon, routeHeap[i].r->nd->lat),
         X (routeHeap[i].r->nd->lon, routeHeap[i].r->nd->lat) + 2,
         Y (routeHeap[i].r->nd->lon, routeHeap[i].r->nd->lat));
     }
-    #else
+    #elif defined (_WIN32)
     for (int j = 0; j <= newWayCnt; j++) {
       int x = X (newWays[j].coord[0][0], newWays[j].coord[0][1]);
       int y = Y (newWays[j].coord[0][0], newWays[j].coord[0][1]);
@@ -2439,8 +2875,10 @@ gint DrawExpose (void)
       }
     }
     #endif
-    text2B.pop ();
-    while (!text2B.empty ()) {
+    LG for (text2B.pop (); !text2B.empty ();  text2B.pop ()) {
+      #ifndef ANDROID_NDK
+      if (pressTime != -1) continue; // Don't render text while dragging
+      #endif
       text2Brendered *t = &text2B.top();
       #ifdef PANGO_VERSION
       PangoRectangle rect;
@@ -2449,7 +2887,7 @@ gint DrawExpose (void)
       struct { double xx, xy, yy, yx; } mat;
       #endif
       int x0 = (t->x + t->x2) / 2, y0 = (t->y + t->y2) / 2;
-      mat.yy = mat.xx = fabs (t->x - t->x2) / (double) t->dst;
+      mat.yy = mat.xx = fabs (double (t->x - t->x2)) / (double) t->dst;
       mat.xy = (t->y - t->y2) / (double)(t->x > t->x2 ? -t->dst : t->dst);
       mat.yx = -mat.xy;
 
@@ -2479,7 +2917,13 @@ gint DrawExpose (void)
           lrint (mat.xy * (rect.height)), lrint (mat.xx * (rect.height)),
           lrint (mat.xx * (rect.width + 10)),
           lrint (mat.yx * (rect.width + 10)));
-        #ifndef NOGTK
+        #ifdef ANDROID_NDK
+    	jstring js = env->NewStringUTF (
+    			string (txt, strcspn (txt, "\n")).c_str ());
+    	env->CallVoidMethod (thiz, drawTeks, js, x0, y0,
+    			(float)mat.xy, (float)mat.xx);
+
+        #elif !defined(NOGTK)
         gdk_draw_layout (GDK_DRAWABLE (draw->window),
           fg_gc /*draw->style->fg_gc[0]*/,
           x0 - (rect.width * mat.xx + rect.height * fabs (mat.xy)) / 2,
@@ -2506,77 +2950,26 @@ gint DrawExpose (void)
         SelectObject (mygc, oldf);
         DeleteObject (customFont);
         #endif
-        if (zoom / clip.width > 20) break;
+        if (zoom / width > 20) break;
         while (*txt != '\0' && *txt++ != '\n') {}
       }
-      text2B.pop ();
-    }
-    for (deque<tsItem>::iterator i = tsList.begin (); i != tsList.end (); i++) {
-      int x, y, j;
-      const char *p = i->cmd.c_str ();
-      for (j = 0; j < 2; j++) {
-        double coef = atof (p);
-        p += strcspn (p, "whWH;");
-        (j ? y : x) = lrint (*p == ';' ? coef : atoi (p + 1) + 
-          coef * (j ? draw->allocation.height : draw->allocation.width));
-        while (*p != '\0' && *p++ != ';') {}
-      //char *xs = i->cmd.c_str (), *ys = xs + strcspn (xs, ";");
-      }
-      #ifndef NOGTK
-      gdk_draw_pixbuf (GDK_DRAWABLE (draw->window), fg_gc, i->pix, 0, 0, x, y,
-        gdk_pixbuf_get_width (i->pix), gdk_pixbuf_get_height (i->pix), GDK_RGB_DITHER_NONE, 0, 0);
-      #else
-      #endif
     }
     free (block);
     if (FollowGPSr && command[0] && command[0] == command[1] && command[0] == command[2]) {
-      DrawPoI (draw->allocation.width / 2, draw->allocation.height / 6,
+      DrawPoI (width / 2, height / 6,
         style[firstElemStyle + command[0]].x + 8); // Always square.big
     }
   } // Not in the menu
   else if (option == searchMode) {
-    for (int i = 0, y = SearchSpacing / 2; i < searchCnt && gosmSstr[i];
-             i++, y += SearchSpacing) {
-      DrawPoI (SearchSpacing / 2, y, Style (gosmSway[i])->x + 4 * IconSet);
-      
-      double dist = sqrt (Sqr ((__int64) clon - gosmSway[i]->clon) +
-          Sqr ((__int64) clat - gosmSway[i]->clat)) * (20000 / 2147483648.0) *
-        cos (LatInverse (clat) * (M_PI / 180));
-      char distance[10]; // Formula inaccurate over long distances hence "Far"
-      sprintf (distance, dist > 998 ? "Far" : dist > 1 ? "%.0lf km" :
-        "%.0lf m", dist > 1 ? dist : dist * 1000);
-      DrawString (SearchSpacing + 33 - 11 * strcspn (distance, " "), y - 10,
-        distance); // Right adjustment is inaccurate
-      
-      #ifndef NOGTK
-      gdk_gc_set_foreground (mygc, &resultArrowColour);
-      gdk_gc_set_line_attributes (mygc, 1,
-        GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
-      #else
-      SelectObject (mygc, GetStockObject (BLACK_PEN));
-      #endif
-      int x = SearchSpacing + 70;
-      __int64 lx = X (gosmSway[i]->clon, gosmSway[i]->clat) - clip.width / 2;
-      __int64 ly = Y (gosmSway[i]->clon, gosmSway[i]->clat) - clip.height / 2;
-      double norm = lx || ly ? sqrt (lx * lx + ly * ly) / 64 : 1;
-      int u = lrint (lx / norm), v = lrint (ly / norm);
-      gdk_draw_line (draw->window, mygc, x + u / 8, y + v / 8,
-        x - u / 8, y - v / 8);
-      gdk_draw_line (draw->window, mygc, x + u / 8, y + v / 8, 
-        x + u / 12 + v / 20, y - u / 20 + v / 12);
-      gdk_draw_line (draw->window, mygc, x + u / 8, y + v / 8,
-        x + u / 12 - v / 20, y + u / 20 + v / 12);
-            
-      string s (gosmSstr[i], strcspn (gosmSstr[i], "\n"));
-      char *name = (char *)(gosmSway[i] + 1) + 1;
-      if (name != gosmSstr[i]) s += " (" +
-                     string (name, strcspn (name, "\n")) + ")";
-      DrawString (SearchSpacing + x, y - 10, s.c_str ());
-
-      gdk_draw_line (draw->window, mygc, 0, y + SearchSpacing / 2,
-        clip.width, y + SearchSpacing / 2);
-    }
-    HandleKeyboard (NULL);
+    #ifndef NOGTK
+    gdk_gc_set_foreground (mygc, &resultArrowColour);
+    gdk_gc_set_line_attributes (mygc, 1,
+       GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
+    #elif defined (_WIN32)
+    SelectObject (mygc, GetStockObject (BLACK_PEN));
+    #endif
+	DisplaySearchResults ();
+    HandleKeyboard (FALSE, 0, 0);
   }
   else if (option == optionMode) {
     for (int i = 0; i < wayPointIconNum; i++) {
@@ -2609,34 +3002,34 @@ gint DrawExpose (void)
     OPTIONS
     #undef o
       0);
-    DrawString (50, draw->allocation.height / 2, optStr);
+    DrawString (50, height / 2, optStr);
   }
   #ifndef NOGTK
   /* Buttons now on the top row 
   gdk_draw_rectangle (draw->window, draw->style->bg_gc[0], TRUE,
-    clip.width - ButtonSize * 20, clip.height - ButtonSize * 60,
-    clip.width, clip.height);
+    width - ButtonSize * 20, height - ButtonSize * 60,
+    width, height);
   for (int i = 0; i < 3; i++) {
     gdk_draw_string (draw->window, f, draw->style->fg_gc[0],
-      clip.width - ButtonSize * 10 - 5, clip.height + (f->ascent - f->descent)
+      width - ButtonSize * 10 - 5, height + (f->ascent - f->descent)
       / 2 - ButtonSize * (20 * i + 10), i == 0 ? "O" : i == 1 ? "-" : "+");
   }
   */
   gdk_window_end_paint (draw->window);
   gdk_flush ();
   #else
-  #ifdef NOGTK
+  #ifdef WIN32
   int i = (Layout > (MenuKey == 0 || option != mapMode ? 0 : 1) ? 3 : 0);
   RECT r;
-  r.left = clip.width - ButtonSize * 20;
-  r.top = clip.height - ButtonSize * 20 * i;
-  r.right = clip.width;
-  r.bottom = clip.height;
+  r.left = width - ButtonSize * 20;
+  r.top = height - ButtonSize * 20 * i;
+  r.right = width;
+  r.bottom = height;
   FillRect (mygc, &r, (HBRUSH) GetStockObject(LTGRAY_BRUSH));
   SelectObject (mygc, sysFont);
   //SetBkMode (mygc, TRANSPARENT);
   while (--i >= 0) {
-    ExtTextOut (mygc, clip.width - ButtonSize * 10 - 5, clip.height - 5 -
+    ExtTextOut (mygc, width - ButtonSize * 10 - 5, height - 5 -
         ButtonSize * (20 * i + 10), 0, NULL, i == 0 ? TEXT ("O") :
         i == 1 ? TEXT ("-") : TEXT ("+"), 1, NULL);
   }
@@ -2645,11 +3038,12 @@ gint DrawExpose (void)
   char coord[64];
   if (ShowCoordinates == 1) {
     if(GpsIdle==999)
-      snprintf (coord, 63, "%9.5lf %10.5lf GPS OFF %s", LatInverse (clat), LonInverse (clon),routeSuccess?"Route":"No Route");
+      snprintf (coord, 63, "%9.5lf %10.5lf zoom=%d GPS OFF %s %sfollowing", LatInverse (clat), LonInverse (clon),zoom,routeSuccess?"Route":"No Route",FollowGPSr?"":"not ");
     else
-      snprintf (coord, 63, "%9.5lf %10.5lf GPS idle %ds %s", LatInverse (clat), LonInverse (clon),GpsIdle,routeSuccess?"Route":"No Route");
+      snprintf (coord, 63, "%9.5lf %10.5lf zoom=%d GPS idle %ds %s %sfollowing", LatInverse (clat), LonInverse (clon),zoom,GpsIdle,routeSuccess?"Route":"No Route",FollowGPSr?"":"not ");
     DrawString (0, 5, coord);
   }
+  #ifdef _WIN32
   else if (ShowCoordinates == 2) {
     MEMORYSTATUS memStat;
     GlobalMemoryStatus (&memStat);
@@ -2658,19 +3052,31 @@ gint DrawExpose (void)
     //ExtTextOut (mygc, 0, 10, 0, NULL, coord, 9, NULL);
   }
   #endif
+  #endif
   #ifdef CAIRO_VERSION
 //  cairo_destroy (cai);
   #endif
-/*
-  clip.height = draw->allocation.height;
-  gdk_gc_set_clip_rectangle (draw->style->fg_gc[0], &clip);
-  gdk_draw_string (draw->window, f, draw->style->fg_gc[0],
-    clip.width/2, clip.height - f->descent, "gosmore");
-  */
+  #ifdef ANDROID_NDK
+  return;
+  #else
   return FALSE;
+  #endif
 }
 
 #ifndef NOGTK
+gint Drag (GtkWidget * /*widget*/, GdkEventMotion *event, void * /*w_cur*/)
+{
+  if (event->state & GDK_BUTTON1_MASK) MouseEv
+          (event->x, event->y, event->time, 1, FALSE);
+  return TRUE;
+}
+
+int Click (GtkWidget * /*widget*/, GdkEventButton *event, void * /*para*/)
+{
+  MouseEv (event->x, event->y, event->time, event->button, TRUE);
+  return TRUE;
+}
+
 GtkWidget *searchW;
 
 int ToggleSearchResults (void)
@@ -2697,6 +3103,7 @@ void HitGtkButton (GtkWidget * /*w*/, void *data)
 
 //------------------------------------------------------------------------
 // Callbacks that are called with the user drops an icon and then binds it
+#if 0
 static gboolean DropOnDraw (GtkWidget *w, GdkDragContext *c, gint /*x*/,
   gint /* y */, guint time, gpointer)
 {
@@ -2706,139 +3113,10 @@ static gboolean DropOnDraw (GtkWidget *w, GdkDragContext *c, gint /*x*/,
   }
   return c->targets ? TRUE : FALSE;
 }
-
-static void ReadTsList (void)
-{
-  FILE *fp = fopen ("main.ts", "r");
-  gsize siz;
-  for (; !tsList.empty (); tsList.pop_back()) g_object_unref (tsList.back().pix);
-  while (fp && fread (&siz, sizeof (siz), 1, fp) == 1) {
-    printf ("Reading %d\n", siz);
-    void *buf = malloc (siz);
-    fread (buf, siz, 1, fp);
-    tsList.push_back (tsItem ());
-    #ifndef NOGTK
-    GInputStream *gis = g_memory_input_stream_new_from_data (buf, siz, NULL);
-    GError *err = NULL;
-    tsList.back ().pix = gdk_pixbuf_new_from_stream (gis, NULL, &err);
-    #else
-    tsList.back ().pix = CreateIconFromResource (buf, siz, TRUE, 0x30000);
-    #endif
-    int c; 
-    while ((c = fgetc (fp)) != '\0') tsList.back ().cmd += c;
-  }
-  if (fp) fclose (fp);
-}
-
-static void DropReceived (GtkWidget */*draw*/, GdkDragContext *c, gint x,
-  gint y, GtkSelectionData *sdata, guint /*ttype*/, guint time, gpointer)
-{
-  //FILE *fp;
-  gchar **arr = sdata != NULL ? gtk_selection_data_get_uris (sdata) : NULL;
-  gchar *f = arr ? g_filename_from_uri (arr[0], NULL, NULL) : NULL;
-//  printf ("x%sx\n", f); //gtk_selection_data_get_text (sdata));
-//  printf ("%p\n", gtk_selection_data_get_pixbuf (sdata));
-//  if (sdata != NULL && sdata->length >= 7) printf ("%s\n----%s----\n", sdata->data,
-//    string ((char*) sdata->data + 7, strcspn ((char*) sdata->data + 7, "\n\r")).c_str());
-
-  GError *err = NULL;
-  tsList.push_back (tsItem ());
-  if ((f && (tsList.back ().pix = gdk_pixbuf_new_from_file (f, &err)))
-      || (tsList.back ().pix = gtk_selection_data_get_pixbuf (sdata))) {
-    //if (ttype == 0) printf ("Data=%s\n", sdata->data);
-    printf ("C %p\n", tsList.back().pix);
-    char a[40];
-    if (draw->allocation.width <= x * 2) x -= draw->allocation.width;
-    if (draw->allocation.height <= y * 2) y -= draw->allocation.height;
-    sprintf (a, "%s %+d; %s %+d; ;", x < 0 ? "1.0 w" : "0.0 w", x,
-                                     y < 0 ? "1.0 h" : "0.0 h", y);
-    tsList.back ().cmd = string (a);
-    
-    GtkWidget *dialog, *dedit;
-    dialog = gtk_dialog_new_with_buttons ("Set icon data", NULL, GTK_DIALOG_MODAL,
-      GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_DELETE, GTK_RESPONSE_NO,
-      GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-    dedit = gtk_entry_new ();
-    gtk_entry_set_text (GTK_ENTRY (dedit), tsList.back ().cmd.c_str ());
-    gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), dedit);
-    gtk_widget_show_all (dialog);
-    int result = gtk_dialog_run (GTK_DIALOG (dialog));
-    if (result == GTK_RESPONSE_OK) {
-      printf ("OK\n");
-      tsList.back ().cmd = string (gtk_entry_get_text (GTK_ENTRY (dedit)));
-    }
-    else if (result == GTK_RESPONSE_NO) {
-      printf ("Delete\n");
-      tsList.pop_back ();
-    }
-    gtk_widget_destroy (dialog);
-
-    FILE *fp = fopen ("main.ts", "w");
-    for (deque<tsItem>::iterator i = tsList.begin (); i != tsList.end (); i++) {
-      gsize siz;
-      gchar *buf;
-      printf ("%p %p\n", err, i->pix);
-      gdk_pixbuf_save_to_buffer (i->pix, &buf, &siz, "ico", &err, NULL);
-      printf ("Saving %u\n", siz);
-  //    gdk_pixbuf_new_from_buffer (
-      fwrite (&siz, sizeof (siz), 1, fp);
-      fwrite (buf, siz, 1, fp);
-      fwrite (i->cmd.c_str (), i->cmd.length () + 1, 1, fp);
-    }
-    fclose (fp);
-    
-    #if 0
-      //(fp = fopen (string ((char*) sdata->data + 7, strcspn ((char*) sdata->data + 7, "\n\r")).c_str(), "r"))) {
-    png_structp pngp = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    printf ("%p\n", pngp);
-    if (pngp) {
-      png_infop infop = png_create_info_struct (pngp);
-      printf ("i %p\n", infop);
-      if (infop && !setjmp (png_jmpbuf (pngp))) {
-        png_init_io (pngp, fp);
-        png_read_png (pngp, infop, PNG_TRANSFORM_IDENTITY |
-          PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING |
-          PNG_TRANSFORM_PACKSWAP /*| PNG_TRANSFORM_GRAY_TO_RGB Missing ?*/, NULL);
-        png_bytep *row = png_get_rows(pngp, infop);
-        printf ("%d %d %d\n", png_get_image_width (pngp, infop), png_get_image_height (pngp, infop),
-          png_get_channels (pngp, infop));
-        for (int i = 0; i < png_get_image_height (pngp, infop); i++) {
-          for (int j = 0; j < png_get_image_width (pngp, infop); j++) {
-            putchar (row[i][j * 4] & 128 ? '*' : ' ');
-          }
-          putchar ('\n');
-        }
-      }
-      png_destroy_read_struct (&pngp, &infop, (png_infopp)NULL);
-    }
-    fclose (fp);
-    #endif
-  }
-  else tsList.pop_back ();
-  g_strfreev (arr);
-  free (f);
-  gtk_drag_finish (c, TRUE, FALSE, time);
-}
-
-void SeUpdate (GtkWidget *w, gpointer p)
-{
-  GdkColor c;
-  if (((intptr_t) p & 0xff) == 2) gtk_color_button_get_color (GTK_COLOR_BUTTON (w), &c);
-  if (((intptr_t) p & 0xff) == 3) printf ("%s ", gtk_font_button_get_font_name (GTK_FONT_BUTTON (w)));
-  if (((intptr_t) p & 0xff) == 4) printf ("%d ", gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (w)));
-  if (((intptr_t) p & 0xff) == 5) printf ("%d ", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)));
-  printf ("%p | %4x %4x %4x\n", p, c.red, c.green, c.blue);
-}
-
-#endif // HEADLESS
-
-#if 0
-void SelectName (GtkWidget * /*w*/, int row, int /*column*/,
-  GdkEventButton * /*ev*/, void * /*data*/)
-{
-}
 #endif
 
+#endif // NOGTK
+
 #endif // HEADLESS
 
 inline void SerializeOptions (FILE *optFile, int r, const TCHAR *pakfile)
@@ -2923,7 +3201,7 @@ int UserInterface (int argc, char *argv[],
   if (strcmp (pakfile, "nopak") == 0 && h) {
     string ddir (string (h) + "/.gosmore");
     mkdir (ddir.c_str (), 0755); // Usually already exists
-    chdir (ddir.c_str ());
+    if (chdir (ddir.c_str ())) perror ("chdir(\".gosmore\")");
     SerializeOptions (optFile, TRUE, NULL);
   }
   else SerializeOptions (optFile, TRUE, pakfile);
@@ -2994,7 +3272,8 @@ int UserInterface (int argc, char *argv[],
     if (!f || (char*)-1L == (char*) (ld = 
              (ldCtrlType *) mmap (NULL, sizeof (*ld), PROT_READ | PROT_WRITE,
                                   MAP_SHARED, fileno (f), 0))
-        || lockf (F_LOCK, fileno (f), sizeof (*ld)) != 0) {
+        //|| lockf (F_LOCK, fileno (f), sizeof (*ld)) != 0) {
+		|| lockf (fileno (f), F_LOCK, sizeof (*ld)) != 0) {
       printf ("Content-Type: text/plain\n\r\n\rLd ctrl error%p %p %s\n\r",
         f, ld, strerror (errno));
       return 0;
@@ -3009,12 +3288,15 @@ int UserInterface (int argc, char *argv[],
     gettimeofday (&ld->inst[myInst].start, &tz);
     if (++ld->free >= MAX_INST) ld->free = 0;
     UpdateLdCtrl (ld->free, calls, 0, 0, sysconf (_SC_NPROCESSORS_ONLN));
-    lockf (F_ULOCK, fileno (f), sizeof (*ld));
+    //lockf (F_ULOCK, fileno (f), sizeof (*ld));
+	lockf (fileno (f), F_ULOCK, sizeof (*ld));
     for (int i = 0; i < ld->inst[myInst].maks && RouteLoop (); i++) {}
-    lockf (F_LOCK, fileno (f), sizeof (*ld));
+    //lockf (F_LOCK, fileno (f), sizeof (*ld));
+	lockf (fileno (f), F_LOCK, sizeof (*ld));
     ld->inst[myInst].start.tv_sec = 0; // Mark that we're done.
     UpdateLdCtrl (ld->free, calls, 0, 0, sysconf (_SC_NPROCESSORS_ONLN));
-    lockf (F_ULOCK, fileno (f), sizeof (*ld));
+    //lockf (F_ULOCK, fileno (f), sizeof (*ld));
+	lockf (fileno (f), F_ULOCK, sizeof (*ld));
     #else
     while (RouteLoop ()) {}
 /*  It is reasonable to assume that there exists a short route in the actual
@@ -3038,29 +3320,57 @@ int UserInterface (int argc, char *argv[],
     else {
       if (!routeSuccess) printf ("Jump\n\r");
       styleStruct *firstS = Style (Way (shortest->nd));
-      double ups = lrint (3.6 / firstS->invSpeed[Vehicle]
-          / firstS->aveSpeed[Vehicle] / (20000 / 2147483648.0) /
-          cos (LatInverse (flat / 2 + tlat / 2) * (M_PI / 180)));
+      double ups = firstS->invSpeed[Vehicle] / 3.6 
+          * firstS->aveSpeed[Vehicle] / 20000000 * 2147483648.0 / 
+          cos (LatInverse (flat / 2 + tlat / 2) * (M_PI / 180));
       // ups (Units per second) also works as an unsigned int.
-
+      double fSegLat = shortest->shortest ?
+        shortest->shortest->nd->lat - shortest->nd->lat : 1;
+      double fSegLon = shortest->shortest ?
+        shortest->shortest->nd->lon - shortest->nd->lon : 1;
+      double fpr = (fSegLat * (flat - shortest->nd->lat) +
+                    fSegLon * (flon - shortest->nd->lon)) /
+                   (Sqr (fSegLat) + Sqr (fSegLon));
+      fpr = fpr > 1 ? 1 : fpr < 0 ? 0 : fpr; // Clamp to [0,1]
       for (; shortest; shortest = shortest->shortest) {
         wayType *w = Way (shortest->nd);
         char *name = (char*)(w + 1) + 1;
         unsigned style= StyleNr(w);
-        printf ("%lf,%lf,%c%s,%s,%.0lf,%.*s\n\r", LatInverse (shortest->nd->lat),
-          LonInverse (shortest->nd->lon), JunctionType (shortest->nd),
+        printf ("%lf,%lf,%c%s,%s,%.0lf,%.*s\n\r",
+          LatInverse (shortest->nd->lat + fSegLat * fpr),
+          LonInverse (shortest->nd->lon + fSegLon * fpr), JunctionType (shortest->nd),
           ((1 << roundaboutR) & (Way (shortest->nd))->bits) ? "r" : "",
           style < sizeof(klasTable)/sizeof(klasTable[0]) ? klasTable[style].desc :
           "(unknown-style)", ((shortest->heapIdx < 0
           ? -shortest->heapIdx : routeHeap[shortest->heapIdx].best) -
           shortest->remain) / ups,
           (int) strcspn (name, "\n"), name);
+        fpr = 0;
+        if (!shortest->shortest) {
+          // I don't know why, but sometimes shortest->dir is wrong. But
+          // AFAIK it only happens at the first or last segment of the way,
+          // so inverting 'dir' solves the problem...
+          ndType *final = shortest->nd + shortest->nd->other[
+            (shortest->nd->other[shortest->dir] ? 0 : 1) ^ shortest->dir];
+          double pr = ((final->lat - shortest->nd->lat) * (double)
+            (tlat - shortest->nd->lat) + (final->lon - shortest->nd->lon) *
+            (double)(tlon - shortest->nd->lon)) /
+            (Sqr ((double)(final->lat - shortest->nd->lat)) +
+             Sqr ((double)(final->lon - shortest->nd->lon)) + 1);
+          pr = pr > 1 ? 1 : pr < 0 ? 0 : pr; // Clamp to [0,1]
+          printf("%lf,%lf,j,(unknown-style),0,fini\n\r",
+      LatInverse (shortest->nd->lat + pr * (final->lat - shortest->nd->lat)),
+      LonInverse (shortest->nd->lon + pr * (final->lon - shortest->nd->lon)));
+//      shortest->dir, shortest->nd->other[shortest->dir]);
+//      shortest->nd->other[1-shortest->dir]);
+      //final->lat - shortest->nd->lat, final->lon - shortest->nd->lon);
+        }
       }
     }
     return 0;
   }
 
-  printf ("%s is in the public domain and comes without warranty\n",argv[0]);
+  printf ("%s is provided as is and any warranties are disclaimed. \n",argv[0]);
   #ifndef HEADLESS
 
   curl_global_init (CURL_GLOBAL_ALL);
@@ -3071,26 +3381,6 @@ int UserInterface (int argc, char *argv[],
 #endif
   draw = gtk_drawing_area_new ();
   gtk_widget_set_double_buffered (draw, FALSE);
-  #if 0 // ndef CHILDREN
-    XID id[3];
-    char sString[50];
-    fread (sString, 4, 1, stdin);
-    fread (id, sizeof (id), 1, stdin);
-    draw->window = gdk_window_foreign_new (id[0]);
-    icons = gdk_pixmap_foreign_new (id[1]);
-    mask = gdk_pixmap_foreign_new (id[2]);
-    for (;;) {
-      #define o(x,min,max) if (fread (&x, sizeof (x), 1, stdin)) {};
-      STATEINFO
-      #undef o
-      //fprintf (stderr, "%d %p | %p %p | %d %d -- %d %d\n", id[0], draw->window,
-      //  icons, mask, id[1], id[2], clon, clat);
-      DrawExpose ();
-      if (write (STDOUT_FILENO, sString, 4) != 4) exit (0);
-      if (fread (sString, 4, 1, stdin) != 1) exit (0);
-      fread (id, sizeof (id), 1, stdin); // Discard
-    }
-  #endif
   gtk_signal_connect (GTK_OBJECT (draw), "expose_event",
     (GtkSignalFunc) DrawExpose, NULL);
   gtk_signal_connect (GTK_OBJECT (draw), "button-release-event",
@@ -3102,7 +3392,6 @@ int UserInterface (int argc, char *argv[],
   gtk_signal_connect (GTK_OBJECT (draw), "scroll_event",
                        (GtkSignalFunc) Scroll, NULL);
 
-#if 0 // New UI editor code                       
   static GtkTargetEntry drawDndTargets[] = {
     { (gchar*) "text/uri-list", 0, 0 },
     { (gchar*) "image/png", 0, 1 /* Will autodetect type on drop */ },
@@ -3111,10 +3400,9 @@ int UserInterface (int argc, char *argv[],
   gtk_drag_dest_set (draw, GTK_DEST_DEFAULT_ALL /* GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT*/, drawDndTargets,
     G_N_ELEMENTS (drawDndTargets), GDK_ACTION_COPY);
                        
-  g_signal_connect (draw, "drag-data-received", G_CALLBACK (DropReceived), NULL);
-  g_signal_connect (draw, "drag-drop", G_CALLBACK (DropOnDraw), NULL);
-  ReadTsList ();
-#endif
+//  g_signal_connect (draw, "drag-data-received", G_CALLBACK (DropReceived), NULL);
+//  g_signal_connect (draw, "drag-drop", G_CALLBACK (DropOnDraw), NULL);
+//  ReadTsList ();
   
   GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_signal_connect (GTK_OBJECT (window), "focus-in-event",
@@ -3269,30 +3557,13 @@ int UserInterface (int argc, char *argv[],
 }
 
 int main (int argc, char *argv[])
-{
-  #if 0 // ifdef CHILDREN
-  if (1) {
-    int cmd[2], result[2];
-    pipe (cmd);
-    pipe (result);
-    child[0].pipe[0] = result[0];
-    child[0].pipe[1] = cmd[1];
-    if (fork () == 0) {
-      dup2 (cmd[0], STDIN_FILENO);
-      dup2 (result[1], STDOUT_FILENO);
-      execl ("./gosmore16", "./gosmore16", NULL);
-      perror ("Starting slave process gosmore16");
-      _exit (1);
-    }
-  }
-  #endif
-  
+{  
   int nextarg = 1;
   bool rebuild = false;
   const char* master = "";
   int bbox[4] = { INT_MIN, INT_MIN, 0x7fffffff, 0x7fffffff };
   
-  setlocale (LC_ALL, ""); /* Ensure decimal sign is "." for NMEA parsing. */
+  setlocale (LC_NUMERIC, "C"); /* Ensure decimal sign is "." for NMEA parsing. */
   
   if (argc > 1 && stricmp (argv[1], "sortRelations") == 0) {
     return SortRelations ();
@@ -3350,7 +3621,7 @@ int main (int argc, char *argv[])
   // close the logfile if it has been opened. No. Rather let libc to it.
   //if (logFP(false)) fclose(logFP(false));
 }
-#else // NOGTK / WIN32 and WINCE Native;
+#elif _WIN32 // NOGTK / WIN32 and WINCE Native;
 //-------------------------- WIN32 and WINCE Native ------------------
 HANDLE port = INVALID_HANDLE_VALUE;
 
@@ -3570,7 +3841,7 @@ LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
        } while (0);
        break;
     case WM_LBUTTONDOWN:
-      pressTime = GetTickCount ();
+      //pressTime = GetTickCount ();
       SetCapture (hWnd);
       break;
     case WM_LBUTTONUP:
@@ -3580,12 +3851,9 @@ LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
         gDisplayOff = FALSE;
         break;
       }
-      GdkEventButton ev;
-      if ((ev.y = HIWORD (lParam) - topBar) > 0) {
-        ev.x = LOWORD (lParam);
-        ev.time = GetTickCount ();
-        ev.button = 1;
-        Click (NULL, &ev, NULL);
+      if (1) {
+        MouseEv ((short) LOWORD (lParam), (short) HIWORD (lParam) - topBar,
+          GetTickCount (), 1, TRUE);
         if (option == LayoutNum) {
           if (Keyboard) MoveWindow(hwndEdit, Layout > 1 ? 8 : 140,
             Layout != 1 ? 5 : -25,
@@ -3602,11 +3870,15 @@ LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
       else if (!Keyboard && LOWORD (lParam) > (Layout > 1 ? 8 : 140)) {
         option = option == searchMode ? mapMode : searchMode;
       }
-      firstDrag[0] = -1;
-      InvalidateRect (hWnd, NULL, FALSE);
+      InvalidateRect (hWnd, NULL, FALSE);
       break;
     case WM_MOUSEMOVE:
-      if (wParam & MK_LBUTTON) {
+      if (wParam & MK_LBUTTON) {
+        MouseEv ((short) LOWORD (lParam), (short) HIWORD (lParam) - topBar,
+                 GetTickCount (), 1, FALSE);
+        InvalidateRect (hWnd, NULL, FALSE);
+      }
+/*      if (wParam & MK_LBUTTON) {
         if (firstDrag[0] >= 0) {
           HDC wdc = GetDC (hWnd);
           int wadj = lastDrag[0] - LOWORD (lParam);
@@ -3620,7 +3892,7 @@ LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
         lastDrag[0] = LOWORD (lParam);
         lastDrag[1] = HIWORD (lParam) - topBar;
         if (firstDrag[0] < 0) memcpy (firstDrag, lastDrag, sizeof (firstDrag));
-      }
+      }*/
       break;
     case WM_MOUSEWHEEL:
       do {
@@ -3856,7 +4128,7 @@ DWORD WINAPI NmeaReader (LPVOID lParam)
             int now;
             now=GetTickCount();
             if(!lastgps) lastgps=now;
-            GpsIdle=(lastgps-now)/1000;
+            GpsIdle=(now-lastgps)/1000;
             lastgps=now;
 	    PostMessage (mWnd, WM_USER + 1, 0, (int) /* intptr_t */ gpsNew);
 	  }
@@ -3889,6 +4161,7 @@ void XmlOut (FILE *newWayFile, const char *k, const char *v)
   }
 }
 
+
 extern "C" {
 int WINAPI WinMain(
     HINSTANCE  hInstance,	  // handle of current instance
@@ -3911,6 +4184,20 @@ int WINAPI WinMain(
   ConvertUTF16toUTF8 ((const UTF16 **) &sStart, sStart + wcslen (argv0),
     &tStart, tStart + sizeof (docPrefix), lenientConversion);
   *tStart = '\0';
+  #ifndef _WIN32_WCE
+  if (strncmp (lpszCmdLine, "rebuild", 7) == 0) {
+    int bbox[4] = { INT_MIN, INT_MIN, 0x7fffffff, 0x7fffffff };
+    _setmaxstdio (1024); // Try to prevent 'Too many open files'
+    RebuildPak("gosmore.pak", "elemstyles.xml", "icons.csv", "", bbox);
+  }
+  else if (lpszCmdLine[0] != '\0') {
+    chdir (docPrefix);
+    char cmdl[200];
+    sprintf (cmdl, "start cmd /C \"7z -so e %s | gosmore rebuild\"", lpszCmdLine);
+    system (cmdl);
+    return 0;
+  }
+  #endif
   #if 0
   GetModuleFileName (NULL, docPrefix, sizeof (docPrefix));
   if (strrchr (docPrefix, '\\')) *strrchr (docPrefix, '\\') = '\0';
diff --git a/libgosm.cpp b/jni/libgosm.cpp
similarity index 90%
rename from libgosm.cpp
rename to jni/libgosm.cpp
index 0cfee84..00c6976 100755
--- a/libgosm.cpp
+++ b/jni/libgosm.cpp
@@ -15,6 +15,9 @@
 #include <map>
 #include <assert.h>
 #include <float.h>
+#ifdef ANDROID_NDK
+#include <android/log.h>
+#endif
 using namespace std;
 
 #include "libgosm.h"
@@ -209,7 +212,7 @@ void GosmSearch (int clon, int clat, const char *key)
         (unsigned) (clon + (clon & (1 << (bits + 16))) * 4 -
                                               (2 << (bits + 16))) >> 16);
       // Now we search through the 4 squares around (clat, clon)
-      for (int mask = 0, maskI = 0; maskI < 4; mask += 0x55555555, maskI++) {
+      for (unsigned mask = 0; (mask & 7) != 4; mask += 0x55555555) {
         int s = GosmIdxSearch (gosmData + idx[count + l],
           (cz ^ (mask & swap)) & ~((4 << (bits << 1)) - 1)) - idx;
 /* Print the square
@@ -363,8 +366,8 @@ routeNodeType *AddNd (ndType *nd, int dir, int cost, routeNodeType *newshort)
       /* Will do later : routeHeap[routeHeapSize].r = n; */
       n->heapIdx = routeHeapSize++;
       n->dir = dir;
-      n->remain = lrint (sqrt (Sqr ((__int64)(nd->lat - rlat)) +
-                               Sqr ((__int64)(nd->lon - rlon))));
+      n->remain = lrint (sqrt (double (Sqr ((__int64)(nd->lat - rlat)) +
+                                       Sqr ((__int64)(nd->lon - rlon)))));
       if (!shortest || n->remain < shortest->remain) shortest = n;
 
       ROUTE_SET_ADDND_COUNT (routeAddCnt + 1);
@@ -503,10 +506,23 @@ void Route (int recalculate, int plon, int plat, int _vehicle, int _fast)
     // In particular, while gosmore is paused while a page is swapped in, the OS can
     // zero some pages for us.
     int dzero = open ("/dev/zero", O_RDWR);
+    #ifndef ANDROID_NDK
     long long ds = sysconf (_SC_PAGESIZE) * (long long) sysconf (_SC_PHYS_PAGES) /
       (sizeof (*routeHeap) + sizeof (*route) + 40);
+    #else
+    // sysconf(_SC_PHYS_PAGES) returned -3 on my Vodaphone 845
+    FILE *minfo = fopen ("/proc/meminfo", "r");
+    char meml[80];
+    while (fgets (meml, sizeof (meml)-1, minfo) && strncmp (meml,
+      "MemTotal:", 9)) {}
+    long long ds = (strncmp (meml, "MemTotal:", 9) ? 100000 :
+      atoi(meml + 9) - 28000) * (long long) 1000 /
+      (sizeof (*routeHeap) + sizeof (*route) + 40);
+    __android_log_print(ANDROID_LOG_DEBUG, "Gosmore", "re %d %d",
+      int(ds), sizeof (*routeHeap) + sizeof (*route) + 40);
+    #endif
     dhashSize = ds > INT_MAX ? INT_MAX : ds;
-    routeHeapMaxSize = lrint (sqrt (dhashSize)) * 3;
+    routeHeapMaxSize = lrint (sqrt ((double) dhashSize)) * 3;
     routeHeap = (routeHeapType*) malloc (routeHeapMaxSize * sizeof (*routeHeap));
     if (!routeHeap || dzero == -1 ||
         (route = (routeNodeType*) mmap (NULL, dhashSize * sizeof (*route),
@@ -605,7 +621,7 @@ int RouteLoop (void)
     int rootIsAdestination = Way (root->nd)->destination & (1 << Vehicle);
     /* Now work through the segments connected to root. */
     
-    unsigned layout[4] = { 0, 0, 0, 0 }, lmask = 1;
+    unsigned layout[4] = { 0, 0, 0, 0 }, lmask = 1, motorRoads = 0;
     ndType *rtother = root->nd + root->nd->other[root->dir], *layoutNd[4];
     // We categorize each segment leaving this junction according to the
     // angle it form with the 'root' segment. The angles are 315 to 45,
@@ -622,6 +638,7 @@ int RouteLoop (void)
           int azimuth = (dot > cross ? 0 : 3) ^ (dot + cross > 0 ? 0 : 1);
           layout[azimuth] |= lmask << dir;
           layoutNd[azimuth] = nd;
+          if ((Way (nd)->bits & (1 << motorcarR))) motorRoads++;
         }
       }
     } while (++nd < ndBase + hashTable[bucketsMin1 + 1] &&
@@ -658,9 +675,9 @@ int RouteLoop (void)
             wayType *w  = Way (restrictItr);
             if (StyleNr (w) >= restriction_no_right_turn &&
                 StyleNr (w) <= restriction_only_straight_on &&
-                atoi ((char*)(w + 1) + 1) == nd->wayPtr &&
+                atol ((char*)(w + 1) + 1) == nd->wayPtr &&
             (StyleNr (w) <= restriction_no_straight_on) ==
-            (atoi (strchr ((char*)(w + 1) + 1, ' ')) == root->nd->wayPtr)) {
+            (atol (strchr ((char*)(w + 1) + 1, ' ')) == root->nd->wayPtr)) {
               break;
             }
           }
@@ -708,19 +725,20 @@ int RouteLoop (void)
           // you will probably have to wait for oncoming traffic.
           }
           
-          if (layout[1] && layout[3] && ((lmask << dir) & layout[0])) {
-            // Straight over a T-junction
-            if ((Way (layoutNd[1])->bits & (1 << motorcarR)) &&
-                (Way (layoutNd[3])->bits & (1 << motorcarR)) && fast) {
-            // And motorcars are allowed on both sides
-              d += (Style (Way (layoutNd[1]))->invSpeed[motorcarR] <
-                    Style (w)->invSpeed[motorcarR] ? 10000 : 3000) *
-                    (fast ? Style (w)->invSpeed[Vehicle] : 1);
+          if (motorRoads > 2 && fast) d += 5000 * (motorRoads - 2) *
+            (fast ? Style (w)->invSpeed[Vehicle] : 1);
+          // T-junction 50m penalty. 4-way junction 100m penalty.
+          
+          if (layout[1] && layout[3] && ((lmask << dir) & layout[0]) &&
+              Style (Way (layoutNd[1]))->invSpeed[bicycleR] > 1.4) {
+            // Straight over a 4 way junction and it is not preferred by
+            // cyclists. Then there is likely to be traffic that will delay us
+//              d += (Style (Way (layoutNd[1]))->invSpeed[motorcarR] <
+//                    Style (w)->invSpeed[motorcarR] && ? 10000 : 3000) *
+//                    (fast ? Style (w)->invSpeed[Vehicle] : 1);
             // Crossing a road that is faster that the road we are traveling
             // on incurs a 100m penalty. If they are equal, the penality is
-            // 30m. TODO: residential crossing residential should be less,
-            // perhaps 20m.
-            }
+            // 30m. 
           }
           
           ndType *n2 = root->nd + root->nd->other[root->dir];
@@ -783,7 +801,7 @@ int GosmInit (void *d, long size)
 {
   if (!d) return FALSE;
   gosmData = (char*) d;
-  ndBase = (ndType *)(gosmData + ((int*)(gosmData + size))[-1]);
+  ndBase = (ndType *)(gosmData + ((unsigned*)(gosmData + size))[-1]);
   bucketsMin1 = ((int *) (gosmData + size))[-2];
   stylecount = ((int *) (gosmData + size))[-3];
   style = (struct styleStruct *)
@@ -795,9 +813,7 @@ int GosmInit (void *d, long size)
   return ndBase && hashTable && *(int*) gosmData == pakHead;
 }
 
-// *** EVERYTHING AFTER THIS POINT IS NOT IN THE WINDOWS BUILDS ***
-
-#ifndef _WIN32
+#if !defined (_WIN32_WCE) && !defined (ANDROID_NDK)
 
 void CalculateInvSpeeds (styleStruct *srec, int styleCnt)
 {
@@ -845,17 +861,41 @@ void GosmLoadAltStyle(const char* elemstylefile, const char* iconscsvfile) {
 /*--------------------------------- Rebuild code ---------------------------*/
 // These defines are only used during rebuild
 
-#include <sys/mman.h>
 #include <libxml/xmlreader.h>
+#ifndef _WIN32
+#include <sys/mman.h>
+#else
+#define PROT_READ  0x1                       /* Page can be read.  */
+#define PROT_WRITE 0x2                       /* Page can be written.  */
+#define MAP_SHARED 0x01                      /* Share changes.  */
+
+void *mmap (void *ptr, long size, long prot, long type, long handle, long offset)
+{
+  HANDLE file_h, map_h;
+
+  file_h = (HANDLE)_get_osfhandle(handle);
+  map_h  = CreateFileMapping(file_h, 0, PAGE_READWRITE, 0, 0, 0);
+  if (!map_h) return (char *)(-1L);
+  ptr = (void *) MapViewOfFile(map_h, FILE_MAP_ALL_ACCESS, 0, 0, 0);
+
+  CloseHandle(map_h);
+  return ptr;
+}
+
+long munmap (void *ptr, long size)
+{
+  return UnmapViewOfFile (ptr) ? 0 : -1;
+}
+                                               
+#endif
 
 #define MAX_BUCKETS (1<<26)
 #define IDXGROUPS 676
 #define NGROUPS 60
-#define MAX_NODES 14000000 /* Max in a group */
 #define S2GROUPS 129 // Last group is reserved for lowzoom halfSegs
-#define NGROUP(x)  ((x) / MAX_NODES % NGROUPS + IDXGROUPS)
+#define NGROUP(x)  ((x) / max_nodes % NGROUPS + IDXGROUPS)
 #define S1GROUPS NGROUPS
-#define S1GROUP(x) ((x) / MAX_NODES % NGROUPS + IDXGROUPS + NGROUPS)
+#define S1GROUP(x) ((x) / max_nodes % NGROUPS + IDXGROUPS + NGROUPS)
 #define S2GROUP(x) ((x) / (MAX_BUCKETS / (S2GROUPS - 1)) + IDXGROUPS + NGROUPS * 2)
 #define PAIRS (16 * 1024 * 1024)
 #define PAIRGROUPS 120
@@ -869,20 +909,29 @@ void GosmLoadAltStyle(const char* elemstylefile, const char* iconscsvfile) {
 #define TO_HALFSEG -1 // Rebuild only
 
 struct halfSegType { // Rebuild only
-  int lon, lat, other, wayPtr;
+  int lon, lat, other;
+  unsigned wayPtr;
+};
+
+struct wayPartType { // Rebuild only
+  int other;
+  unsigned wayPtr;
+  long long id;
 };
 
 struct nodeType {
-  int id, lon, lat;
+  long long id;
+  int lon, lat;
 };
 
 char *data;
+int max_nodes;
 
-inline nodeType *FindNode (nodeType *table, int id)
+inline nodeType *FindNode (nodeType *table, long long id)
 {
   unsigned hash = id;
   for (;;) {
-    nodeType *n = &table[hash % MAX_NODES];
+    nodeType *n = &table[hash % max_nodes];
     if (n->id < 0 || n->id == id) return n;
     hash = hash * (__int64) 1664525 + 1013904223;
   }
@@ -948,7 +997,7 @@ int LoadElemstyles(/* in */ const char *elemstylesfname,
    //------------------------- elemstyle.xml : --------------------------
     int ruleCnt = 0, styleCnt = firstElemStyle;
     // zero-out elemstyle-to-stylestruct mappings
-    FILE *icons_csv = fopen (iconsfname, "r");
+    FILE *icons_csv = fopen (iconsfname, "rb");
     xmlTextReaderPtr sXml = xmlNewTextReaderFilename (elemstylesfname);
     if (!sXml || !icons_csv) {
       fprintf (stderr, "Either icons.csv or elemstyles.xml not found\n");
@@ -1423,6 +1472,11 @@ deque<string> Osm2Gosmore (int /*id*/, k2vType &k2v, wayType &w,
     s.aveSpeed[bicycleR] = 20;
     // then we say cyclists will love it.
   }
+  for (m = membership; m; m = Next (m)) {
+    if (Find (m, "route")) {
+      result.push_back (string (Find (m, "relation_id")) + '\n');
+    } // If it's a route add it's relation_id and index it.
+  }
   
   if (isRelation && k2v["restriction"] && wayRole["from"] && wayRole["to"]) {
     result.push_front (
@@ -1451,15 +1505,22 @@ deque<string> Osm2Gosmore (int /*id*/, k2vType &k2v, wayType &w,
     }
   }
   // Now adjust for track type.
-  if (k2v["tracktype"] && isdigit (k2v["tracktype"][5])) {
-    s.aveSpeed[motorcarR] *= ('6' - k2v["tracktype"][5]) / 5.0;
-    // Alternatively use ... (6 - atoi (k2v["tracktype"] + 5)) / 5.0;
-    // TODO: Mooaar
+  if ((k2v["tracktype"] && isdigit (k2v["tracktype"][5])) ||
+    (k2v["highway"] && strcmp (k2v["highway"], "track") == 0)) {
+    // many tracks don't have a tracktype, assume them as rather slow
+    int tracktype = 2;
+    if (k2v["tracktype"] && isdigit (k2v["tracktype"][5]))
+      tracktype = atoi (k2v["tracktype"] + 5);
+    s.aveSpeed[motorcarR] *= (6 - tracktype) / 5.0;
+    if (tracktype >= 3) s.aveSpeed[bicycleR] *= (6 - tracktype) / 4.0;
+    if (tracktype == 5) s.aveSpeed[footR] *= 0.8;
   }
   if ((w.bits & (1 << onewayR)) && !(k2v["cycleway"] &&
     (strcmp (k2v["cycleway"], "opposite_lane") == 0 ||
      strcmp (k2v["cycleway"], "opposite_track") == 0 ||
-     strcmp (k2v["cycleway"], "opposite") == 0))) {
+     strcmp (k2v["cycleway"], "opposite") == 0)) &&
+     !(k2v["oneway:bicycle"] && (strcmp (k2v["oneway:bicycle"], "0") == 0 ||
+                                strcmp (k2v["oneway:bicycle"], "no") == 0))) {
     // On oneway roads, cyclists are only allowed to go in the opposite
     // direction, if the cycleway tag exist and starts with "opposite"
     w.bits |= 1 << bicycleOneway;
@@ -1476,25 +1537,25 @@ deque<string> Osm2Gosmore (int /*id*/, k2vType &k2v, wayType &w,
 ndType *LFollow (ndType *nd, ndType *ndItr, wayType *w, int forward)
 { // Helper function when a way is copied into lowzoom table.
   if (forward) {
-    nd += nd->other[1];
-    if (nd->other[1]) return nd;
+    nd += nd->other[0];
+    if (nd->other[0]) return nd;
   }
   if (nd->lat == nd[1].lat && nd->lon == nd[1].lon) {
     if ((nd->lat != nd[2].lat || nd->lon != nd[2].lon) &&
         (nd->lat != nd[-1].lat || nd->lon != nd[-1].lon ||
          // If there is a 3rd object there,
-         (nd[-1].other[0] == 0 && nd[-1].other[0] == 0)) &&
+         (nd[-1].other[1] == 0 && nd[-1].other[1] == 0)) &&
         // then it must be a node
-        nd + 1 != ndItr && nd[1].other[!forward ? 1 : 0] == 0
+        nd + 1 != ndItr && nd[1].other[forward ? 1 : 0] == 0
         // Must not loop back to start and must not be T juntion
         && StyleNr (w) == StyleNr ((wayType*)(data + nd[1].wayPtr))) nd++;
   }
   else if (nd->lat == nd[-1].lat && nd->lon == nd[-1].lon &&
            (nd->lat != nd[-2].lat || nd->lon != nd[-2].lon ||
             // If there is a 3rd object there,
-            (nd[-2].other[0] == 0 && nd[-2].other[0] == 0)) &&
+            (nd[-2].other[1] == 0 && nd[-2].other[1] == 0)) &&
             // then it must be a node
-           nd - 1 != ndItr && nd[-1].other[!forward ? 1 : 0] == 0
+           nd - 1 != ndItr && nd[-1].other[forward ? 1 : 0] == 0
            // Must not loop back to start and must not be T juntion
            && StyleNr (w) == StyleNr ((wayType*)(data + nd[-1].wayPtr))) nd--;
   // If nd ends at a point where exactly two ways meet and they have the same
@@ -1510,10 +1571,10 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
 
   int rebuildCnt = 0;
   FILE *pak, *masterf;
-  int ndStart;
+  unsigned ndStart;
   wayType *master = NULL;
   if (strcmp(masterpakfile,"")) {
-    if (!(masterf = fopen64 (masterpakfile, "r")) ||
+    if (!(masterf = fopen64 (masterpakfile, "rb")) ||
 	fseek (masterf, -sizeof (ndStart), SEEK_END) != 0 ||
 	fread (&ndStart, sizeof (ndStart), 1, masterf) != 1 ||
 	(long)(master = (wayType *)mmap (NULL, ndStart, PROT_READ,
@@ -1524,31 +1585,33 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
     }
   }
   
-  if (!(pak = fopen64 (pakfile, "w+"))) {
+  if (!(pak = fopen64 (pakfile, "w+b"))) {
     fprintf (stderr, "Cannot create %s\n",pakfile);
     return 2;
   }
   FWRITE (&pakHead, sizeof (pakHead), 1, pak);
 
   //------------------------ elemstylesfile : -----------------------------
-  styleStruct srec[2 << STYLE_BITS];
-  elemstyleMapping eMap[2 << STYLE_BITS];
-  memset (&srec, 0, sizeof (srec));
-  memset (&eMap, 0, sizeof (eMap));
+  styleStruct *srec =
+    (styleStruct*) calloc ((2 << STYLE_BITS), sizeof (*srec));
+  elemstyleMapping *eMap =
+    (elemstyleMapping*) calloc ((2 << STYLE_BITS), sizeof (*eMap));
   
   int elemCnt = LoadElemstyles(elemstylefile, iconscsvfile,
 				srec, eMap), styleCnt = elemCnt;
   
   
   //------------------ OSM Data File (/dev/stdin) : ------------------------
+  max_nodes = ((time (NULL) - 1351071438) * (long long) 20 + 1980820697) /
+    NGROUPS; // Linear extrapolation from Oct 2012 at 20 nodes / second.
   xmlTextReaderPtr xml = xmlReaderForFd (STDIN_FILENO, "", NULL, 0);
   FILE *groupf[PAIRGROUP2 (0) + PAIRGROUPS2];
   char groupName[PAIRGROUP2 (0) + PAIRGROUPS2][9];
   for (int i = 0; i < PAIRGROUP2 (0) + PAIRGROUPS2; i++) {
     sprintf (groupName[i], "%c%c%d.tmp", i / 26 % 26 + 'a', i % 26 + 'a',
 	     i / 26 / 26);
-    if (i < S2GROUP (0) && !(groupf[i] = fopen64 (groupName[i], "w+"))) {
-      fprintf (stderr, "Cannot create temporary file.\n"
+    if (i < S2GROUP (0) && !(groupf[i] = fopen64 (groupName[i], "w+b"))) {
+      perror ("Cannot create temporary file.\n"
 	       "Possibly too many open files, in which case you must run "
 	       "ulimit -n or recompile\n");
       return 9;
@@ -1567,15 +1630,15 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
 #endif
     
   nodeType nd;
-  halfSegType s[2];
+  wayPartType wp[2];
   int nOther = 0, lowzOther = FIRST_LOWZ_OTHER, isNode = 0;
   int yesMask = 0, noMask = 0;
   struct {
     wayType *w; // Pointer to the first version in the master file.
     int off;
   } *wayFseek = NULL;
-  int wStyle = elemCnt, ref = 0;
-  int relationType = 0, onewayReverse = 0;
+  int wStyle = elemCnt, relationType = 0, onewayReverse = 0;
+  long long ref = 0;
   vector<int> wayMember;
   map<int,int> wayId;
   wayType w;
@@ -1619,7 +1682,7 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
   }
   
   char *relationTable;
-  FILE *relationTableFile = fopen ("relations.tbl", "r");
+  FILE *relationTableFile = fopen ("relations.tbl", "rb");
   if (!relationTableFile || fseek (relationTableFile, 0, SEEK_END) != 0 ||
       (relationTable = (char*) mmap (NULL, ftell (relationTableFile), PROT_READ,
         MAP_SHARED, fileno (relationTableFile), 0)) == (char*)-1) {
@@ -1630,8 +1693,8 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
   char *tag_k = NULL, *role = NULL; //, *tags = (char *) BAD_CAST xmlStrdup (BAD_CAST "");
   //char *nameTag = NULL;
   k2vType k2v, wayRole; // wayRole should be a vector< struct{char*,int} > ...
-  deque<int> wayNd;
-  map<int, deque<int> > outer;
+  deque<long long> wayNd;
+  map<int, deque<long long> > outer;
   REBUILDWATCH (while (xmlTextReaderRead (xml) == 1)) {
     char *name = (char *) BAD_CAST xmlTextReaderName (xml);
     //xmlChar *value = xmlTextReaderValue (xml); // always empty
@@ -1642,10 +1705,10 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
 	char *aname = (char *) BAD_CAST xmlTextReaderName (xml);
 	char *avalue = (char *) BAD_CAST xmlTextReaderValue (xml);
 	//        if (xmlStrcasecmp (name, "node") == 0) 
-	if (stricmp (aname, "id") == 0) nd.id = atoi (avalue);
+	if (stricmp (aname, "id") == 0) nd.id = atoll (avalue);
 	if (stricmp (aname, "lat") == 0) nd.lat = Latitude (atof (avalue));
 	if (stricmp (aname, "lon") == 0) nd.lon = Longitude (atof (avalue));
-	if (stricmp (aname, "ref") == 0) ref = atoi (avalue);
+	if (stricmp (aname, "ref") == 0) ref = atoll (avalue);
 	if (stricmp (aname, "type") == 0) relationType = avalue[0];
 
 #define K_IS(x) (stricmp (tag_k, x) == 0)
@@ -1734,7 +1797,7 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
         while (!wayMember.empty ()) {
           int idx;
           for (idx = wayMember.size () - 1; !outer[wayMember[idx]].empty () ; idx--) {
-            deque<int> *o = &outer[wayMember[idx]];
+            deque<long long> *o = &outer[wayMember[idx]];
             if (wayNd.empty () || wayNd.back () == o->front () || idx == 0) {
               if (!wayNd.empty () && wayNd.back () == o->front ()) wayNd.pop_back ();
               wayNd.insert (wayNd.end (), o->begin (), o->end ());
@@ -1776,7 +1839,7 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
         }
         membershipType membership =
           *relationTable == (isNode ? 'n' : nameIsRelation ? 'x' : 'w') &&
-	      atoi (relationTable + 1) == nd.id ? relationTable : NULL;
+	      atoll (relationTable + 1) == nd.id ? relationTable : NULL;
 
         for (membershipType m = membership; m; m = Next (m)) {
           if (strcmp (Role (m), "inner") == 0 && wStyle == elemCnt) {
@@ -1788,7 +1851,7 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
             }
           }
           else if (strcmp (Role (m), "outer") == 0) {
-            outer[nd.id] = deque<int> ();
+            outer[nd.id] = deque<long long> ();
             outer[nd.id].insert (outer[nd.id].end (), wayNd.begin (), wayNd.end ());
           }
 	}
@@ -1805,31 +1868,33 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
 	if (wStyle == elemCnt /* 1 trick that did help enough to make files < 400MB
 	  || (!k2v["name"] && srec[wStyle].areaColour != -1)*/ ) wayNd.clear ();
 	else {
-	  s[0].other = -2;
+	  wp[0].other = -2;
 	  while (!wayNd.empty ()) {
-            s[0].wayPtr = ftell (pak);
-            s[1].wayPtr = TO_HALFSEG;
-            s[1].other = s[0].other + 1;
-            s[0].lat = onewayReverse ? wayNd.back () : wayNd.front ();
+            wp[0].wayPtr = ftell (pak);
+            wp[1].wayPtr = TO_HALFSEG;
+            wp[1].other = wp[0].other + 1;
+            wp[0].id = onewayReverse ? wayNd.back () : wayNd.front ();
             /*if (lowzListCnt >=
                 int (sizeof (lowzList) / sizeof (lowzList[0]))) lowzListCnt--;
             lowzList[lowzListCnt++] = s[0].lat; */
             if (onewayReverse) wayNd.pop_back ();
             else wayNd.pop_front ();
-            s[0].other = wayNd.empty () ? -2 : nOther++ * 2;
-            FWRITE (s, sizeof (s), 1, groupf[S1GROUP (s[0].lat)]);
+            wp[0].other = wayNd.empty () ? -2 : nOther++ * 2;
+            FWRITE (wp, sizeof (wp), 1, groupf[S1GROUP (wp[0].id)]);
           }
 	  if (nameIsNode && (!wayFseek || wayFseek->off)) {
-	    s[0].lat = nd.id; // Create 2 fake halfSegs
-	    s[0].wayPtr = ftell (pak);
-	    s[1].wayPtr = TO_HALFSEG;
-	    s[0].other = -2; // No next
-	    s[1].other = -1; // No prev
+	    wp[0].id = nd.id; // Create 2 fake halfSegs
+	    wp[0].wayPtr = ftell (pak);
+	    wp[1].wayPtr = TO_HALFSEG;
+	    wp[0].other = -2; // No next
+	    wp[1].other = -1; // No prev
 	    //lowzList[lowzListCnt++] = nd.id;
-            FWRITE (s, sizeof (s), 1, groupf[S1GROUP (s[0].lat)]);
+            FWRITE (wp, sizeof (wp), 1, groupf[S1GROUP (wp[0].id)]);
 	  }
 	  
-	  w.bits |= ~noMask & (yesMask | (eMap[wStyle].defaultRestrict &
+	  w.bits |= ~noMask & ((yesMask & (1 << accessR)) 
+	                       ? yesMask | ((1 << onewayR) - (1 << (accessR + 1)))
+	                       : yesMask | (eMap[wStyle].defaultRestrict &
 					  ((noMask & (1 << accessR)) ? (1 << onewayR) : ~0)));
 	  if (w.destination & (1 << accessR)) w.destination = ~0;
 	  memcpy (&srec[styleCnt], &srec[wStyle], sizeof (srec[0]));
@@ -1946,6 +2011,7 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
     xmlFree (name);
   } // While reading xml
   wayId.clear ();
+  fprintf (stderr, "nOther=%d FIRST_LOWZ_OTHER=%d\n", nOther, FIRST_LOWZ_OTHER);
   assert (nOther * 2 < FIRST_LOWZ_OTHER);
   bucketsMin1 = (nOther >> 5) | (nOther >> 4);
   bucketsMin1 |= bucketsMin1 >> 2;
@@ -1956,27 +2022,32 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
   
   for (int i = 0; i < IDXGROUPS; i++) fclose (groupf[i]);
   for (int i = S2GROUP (0); i < PAIRGROUP2 (0) + PAIRGROUPS2; i++) {
-    assert (groupf[i] = fopen64 (groupName[i], "w+"));
+    assert (groupf[i] = fopen64 (groupName[i], "w+b"));
   } // Avoid exceeding ulimit
   
-  nodeType *nodes = (nodeType *) malloc (sizeof (*nodes) * MAX_NODES);
+  nodeType *nodes = (nodeType *) malloc (sizeof (*nodes) * max_nodes);
   if (!nodes) {
     fprintf (stderr, "Out of memory. Reduce MAX_NODES and increase GRPs\n");
     return 3;
   }
+  halfSegType s[2];
   for (int i = NGROUP (0); i < NGROUP (0) + NGROUPS; i++) {
     rewind (groupf[i]);
-    memset (nodes, -1, sizeof (*nodes) * MAX_NODES);
+    memset (nodes, -1, sizeof (*nodes) * max_nodes);
     REBUILDWATCH (while (fread (&nd, sizeof (nd), 1, groupf[i]) == 1)) {
       memcpy (FindNode (nodes, nd.id), &nd, sizeof (nd));
     }
     fclose (groupf[i]);
     unlink (groupName[i]);
     rewind (groupf[i + NGROUPS]);
-    REBUILDWATCH (while (fread (s, sizeof (s), 1, groupf[i + NGROUPS])
+    REBUILDWATCH (while (fread (wp, sizeof (wp), 1, groupf[i + NGROUPS])
 			 == 1)) {
-      nodeType *n = FindNode (nodes, s[0].lat);
+      nodeType *n = FindNode (nodes, wp[0].id);
       //if (n->id == -1) printf ("** Undefined node %d\n", s[0].lat);
+      s[0].other = wp[0].other;
+      s[1].other = wp[1].other;
+      s[0].wayPtr = wp[0].wayPtr;
+      s[1].wayPtr = wp[1].wayPtr;
       s[0].lat = s[1].lat = n->id != -1 ? n->lat : INT_MIN;
       s[0].lon = s[1].lon = n->id != -1 ? n->lon : INT_MIN;
       FWRITE (s, sizeof (s), 1,
@@ -2028,6 +2099,8 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
   ndWrite.other[0] = ndWrite.other[1] = 0;
   FWRITE (&ndWrite, sizeof (ndWrite), 1, pak); // Insert 'stopper' record
 
+  assert (ftell (pak) < (1LL<<32));
+  // If this assert fails, wayPtr no longer fits in 32 bits
   ndStart = ftell (pak);
   
   int *pairing = (int *) malloc (sizeof (*pairing) * PAIRS);
@@ -2094,6 +2167,7 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
   fseek (pak, ftell (pak), SEEK_SET);
   vector<halfSegType> lseg;
   ndBase = (ndType*)(data + ndStart);
+  #ifndef ONLY_ROUTING
   REBUILDWATCH (for (ndType *ndItr = ndBase;
                 ndItr < ndBase + hashTable[bucketsMin1 + 1]; ndItr++)) {
   //while (fread (&ndWrite, sizeof (ndWrite), 1, pak) == 1)) {
@@ -2124,12 +2198,12 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
     // and the lats & lons have been dereferenced previously. So the pairing is
     // simplified a lot.
     ndType *prev = LFollow (ndItr, ndItr, way, 0);
-    if (!ndItr->other[0] && prev->wayPtr >= ndItr->wayPtr) {
+    if (!ndItr->other[1] && prev->wayPtr >= ndItr->wayPtr) {
       int length = 0;
       ndType *end;
-      for (end = ndItr; end->other[1]; end = LFollow (end, ndItr, way, 1)) {
-        length += lrint (sqrt (Sqr ((double)(end->lat - end[end->other[1]].lat)) +
-                               Sqr ((double)(end->lon - end[end->other[1]].lon))));
+      for (end = ndItr; end->other[0]; end = LFollow (end, ndItr, way, 1)) {
+        length += lrint (sqrt (Sqr ((double)(end->lat - end[end->other[0]].lat)) +
+                               Sqr ((double)(end->lon - end[end->other[0]].lon))));
         if (prev != ndItr && end->wayPtr < ndItr->wayPtr) break;
         // If it is circular and we didn't start at the way with the lowest
         // wayPtr, then we abort
@@ -2180,6 +2254,7 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
       } // If the way belongs in the lowzoom
     } // If it was the start of a way
   } // For each highzoom nd
+  #endif
   REBUILDWATCH (qsort (&lseg[0], lseg.size () / 2, sizeof (lseg[0]) * 2, 
     (int (*)(const void *, const void *))HalfSegCmp));
   int *lpair = new int[lowzOther - FIRST_LOWZ_OTHER];
@@ -2211,7 +2286,7 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
   }
   
   REBUILDWATCH (for (int i = 0; i < IDXGROUPS; i++)) {
-    assert (groupf[i] = fopen64 (groupName[i], "r+"));
+    assert (groupf[i] = fopen64 (groupName[i], "r+b"));
     fseek (groupf[i], 0, SEEK_END);
     int fsize = ftell (groupf[i]);
     if (fsize > 0) {
@@ -2236,7 +2311,7 @@ int RebuildPak(const char* pakfile, const char* elemstylefile,
 	  bucketsMin1 + (bucketsMin1 >> 7) + 3, pak);
 	  
   CalculateInvSpeeds (srec, styleCnt);
-  FWRITE (&srec, sizeof (srec[0]), styleCnt, pak);
+  FWRITE (srec, sizeof (srec[0]), styleCnt, pak);
   FWRITE (&styleCnt, sizeof(styleCnt), 1, pak); // File ends with these
   FWRITE (&bucketsMin1, sizeof (bucketsMin1), 1, pak); // 3 variables
   FWRITE (&ndStart, sizeof (ndStart), 1, pak); /* for ndBase */
@@ -2258,7 +2333,8 @@ int XmlTee (void * /*context*/, char *buf, int len)
 int XmlClose (void */*context*/) { return 0; }
 
 struct memberType {
-  int ref, type;
+  int type;
+  long long ref;
   const char *role, *tags;
 };
 
@@ -2298,11 +2374,23 @@ int SortRelations (void)
       #endif
       
       rel = rel || stricmp (name, "relation") == 0;
-      if (stricmp (name, "relation") == 0 && rStart < member.size ()) {
+      if (stricmp (name, "relation") == 0) { // && rStart < member.size ()) {
         while (rStart < member.size ()) member[rStart++].tags = s->c_str ();
         s = new string (); // It leaks memory, but it cannot be freed until
                            // moments before exit.
+        while (xmlTextReaderMoveToNextAttribute (xml)) {
+          char *aname = (char *) BAD_CAST xmlTextReaderName (xml);  
+          if (stricmp (aname, "id") == 0) {
+            char *avalue = (char *) BAD_CAST xmlTextReaderValue (xml);
+            *s += "relation_id\nr";
+            *s += avalue;
+            *s += '\n';
+            xmlFree (avalue);
+          }
+          xmlFree (aname);
+        }
       }
+      
       if (rel && (stricmp (name, "member") == 0 || stricmp (name, "tag") == 0)) {
         if (name[0] == 'm') member.push_back (memberType ());
         while (xmlTextReaderMoveToNextAttribute (xml)) {
@@ -2311,7 +2399,7 @@ int SortRelations (void)
           if (stricmp (aname, "type") == 0) {
             member.back ().type = avalue[0] == 'r' ? 'x' : avalue[0];
           }
-          else if (stricmp (aname, "ref") == 0) member.back ().ref = atoi (avalue);
+          else if (stricmp (aname, "ref") == 0) member.back ().ref = atoll (avalue);
           else if (name[0] == 't' && stricmp (aname, "k") == 0) {
             *s += avalue;
             *s += '\n';
@@ -2331,7 +2419,7 @@ int SortRelations (void)
     }
   }
   #ifdef MKDENSITY_CSV
-  FILE *df = fopen ("density.csv", "w");
+  FILE *df = fopen ("density.csv", "wb");
   for (lat = 1023; lat >= 0; lat--) {
     for (lon = 0; lon < 1024; lon++) {
       fprintf (df, "%d%c", cnt[lat * 1024 + lon], lon == 1023 ? '\n' : ' ');
@@ -2342,9 +2430,9 @@ int SortRelations (void)
   while (rStart < member.size ()) member[rStart++].tags = s->c_str ();
   qsort (&member[0], member.size (), sizeof (member[0]),
          (int (*)(const void *, const void *)) MemberCmp);
-  FILE *idx = fopen ("relations.tbl", "w");
+  FILE *idx = fopen ("relations.tbl", "wb");
   for (unsigned i = 0; i < member.size (); i++) {
-    fprintf (idx, "%c%d%c%s%c", member[i].type, member[i].ref, '\0', member[i].role, '\0');
+    fprintf (idx, "%c%lld%c%s%c", member[i].type, member[i].ref, '\0', member[i].role, '\0');
     for (const char *ptr = member[i].tags; *ptr; ptr += strcspn (ptr, "\n") + 1) {
       fprintf (idx, "%.*s%c", (int) strcspn (ptr, "\n"), ptr, '\0');
     }
diff --git a/libgosm.h b/jni/libgosm.h
similarity index 98%
rename from libgosm.h
rename to jni/libgosm.h
index 07693e2..c467fd2 100755
--- a/libgosm.h
+++ b/jni/libgosm.h
@@ -17,7 +17,9 @@ typedef int intptr_t;
 #endif
 
 #ifndef _WIN32
+#ifndef ANDROID_NDK
 #include <libxml/xmlreader.h>
+#endif
 #include <inttypes.h>
 #define stricmp strcasecmp
 typedef long long __int64;
@@ -26,7 +28,7 @@ typedef long long __int64;
 #define M_PI 3.14159265358979323846 // Not in math ??
 #endif
 
-#if __FreeBSD__ || __APPLE__  // Thanks to Ted Mielczarek & Dmitry
+#if __FreeBSD__ || __APPLE__ || ANDROID_NDK
 #define fopen64(x,y) fopen(x,y)
 #endif
 
@@ -46,7 +48,7 @@ typedef long long __int64;
 #endif
 
 #define Sqr(x) ((x)*(x))
-inline int isqrt (int x) { return lrint (sqrt (x)); } // Optimize this ?
+inline int isqrt (int x) { return lrint (sqrt ((double)x)); } // Optimize this ?
 
 #define TILEBITS (18)
 #define TILESIZE (1<<TILEBITS)
@@ -270,7 +272,7 @@ enum {
  s (landuse, retail,          "retail area"     , "") \
  s (landuse, commercial,      "commercial area" , "") \
  s (landuse, construction,    "construction area" , "") \
- s (landuse, reservoir,       "reservoir"       , "") \
+ s (natural, coastline,       "coastline"       , "") \
  s (natural, water,           "lake / dam"      , "") \
  s (landuse, basin,           "basin"           , "") \
  s (landuse, landfill,        "landfill"        , "") \
@@ -322,7 +324,8 @@ struct styleStruct {
 };
 
 struct ndType {
-  int wayPtr, lat, lon, other[2];
+  unsigned wayPtr;
+  int lat, lon, other[2];
 };
 /* This struct takes up a lot of space, but compressing is possible: If
 other is encoded as byte offset from the current position, it should typically
@@ -476,7 +479,7 @@ int GosmInit (void *d, long size);
 
 // *** EVERYTHING AFTER THIS POINT IS NOT IN THE WINDOWS BUILDS ***
 
-#ifndef _WIN32
+#ifndef _WIN32_WCE
 
 void GosmLoadAltStyle(const char* elemstylefile, const char* iconscsvfile);
 
diff --git a/jni/openglespolygon.cpp b/jni/openglespolygon.cpp
new file mode 100755
index 0000000..53e7bb7
--- /dev/null
+++ b/jni/openglespolygon.cpp
@@ -0,0 +1,532 @@
+/* Copyright (C) 2011 Nic Roets as detailed in the README file. */
+#ifndef HEADLESS
+#include <assert.h>
+#include <string.h>
+#include <malloc.h>
+#ifdef ANDROID_NDK
+#include <jni.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <android/log.h>
+#else
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#endif
+#include "openglespolygon.h"
+#define LG  //__android_log_print (ANDROID_LOG_WARN, "Gosmore", "%d", __LINE__);
+
+using namespace std;
+
+typedef long long calcType; // Used to prevent overflows when
+                            // multiplying two GdkPoint fields
+
+int edgeCmp /*::operator()*/(const PolygonEdge *a, const PolygonEdge *b)
+{
+  const FixedPoint *ap = a->pt, *bp = b->pt,
+    *st = a->prev.y < b->prev.y ? &a->prev : &b->prev;
+  calcType cross;
+  if (a->pt == &a->prev) return a->prev.x < 0; // left and right borders
+  if (b->pt == &b->prev) return b->prev.x > 0;
+  while ((cross = (ap->x - st->x) * (calcType)(bp->y - st->y) -
+                  (ap->y - st->y) * (calcType)(bp->x - st->x)) == 0) {
+    if (ap->y < bp->y) {
+      st = ap;
+      ap += a->delta;
+      if (ap - a->pt >= a->cnt || ap - a->pt + a->cnt <= 0) {
+        if (!a->continues) return !b->isLeft; // Edges are the same
+        a++;
+        ap = a->pt;
+      }
+    }
+    else {
+      st = bp;
+      bp += b->delta;
+      if (bp - b->pt >= b->cnt || bp - b->pt + b->cnt <= 0) {
+        if (!b->continues) return !b->isLeft; // Edges are the same
+        b++;
+        bp = b->pt;
+      }
+    }
+  }
+  return cross < 0;
+}
+
+//-------------------[ Start of AA tree code ]---------------------------
+#define AATREE_NOREBALANCE 1
+
+struct PolygonEdge *First (struct PolygonEdge *root)
+{
+  if (!root->left) return NULL;
+  while (root->left) root = root->left;
+  return root;
+}
+
+struct PolygonEdge *Next (struct PolygonEdge *n)
+{
+  if (n->right) {
+    n = n->right;
+    while (n->left) n = n->left;
+  }
+  else {
+    while (n->parent && n->parent->right == n) n = n->parent;
+    // Follow the parent link while it's pointing to the left.
+    n = n->parent; // Follow one parent link pointing to the right
+
+    if (!n->parent) return NULL;
+    // The last PolygonEdge is the root, because it has nothing to it's right
+  }
+  return n;
+}
+
+struct PolygonEdge *Prev (struct PolygonEdge *n)
+{
+  if (n->left) {
+    n = n->left;
+    while (n->right) n = n->right;
+  }
+  else {
+    while (n->parent && n->parent->left == n) n = n->parent;
+    // Follow the parent link while it's pointing to the left.
+    if (!n->parent) return NULL;
+    // The last PolygonEdge is the root, because it has nothing to it's right
+    n = n->parent; // Follow one parent link pointing to the right
+  }
+  return n;
+}
+
+void Skew (struct PolygonEdge *oldparent)
+{
+  struct PolygonEdge *newp = oldparent->left;
+  
+  if (oldparent->parent->left == oldparent) oldparent->parent->left = newp;
+  else oldparent->parent->right = newp;
+  newp->parent = oldparent->parent;
+  oldparent->parent = newp;
+  
+  oldparent->left = newp->right;
+  if (oldparent->left) oldparent->left->parent = oldparent;
+  newp->right = oldparent;
+  
+  oldparent->level = oldparent->left ? oldparent->left->level + 1 : 1;
+}
+
+int Split (struct PolygonEdge *oldparent)
+{
+  struct PolygonEdge *newp = oldparent->right;
+  
+  if (newp && newp->right && newp->right->level == oldparent->level) { 
+    if (oldparent->parent->left == oldparent) oldparent->parent->left = newp;
+    else oldparent->parent->right = newp;
+    newp->parent = oldparent->parent;
+    oldparent->parent = newp;
+    
+    oldparent->right = newp->left;
+    if (oldparent->right) oldparent->right->parent = oldparent;
+    newp->left = oldparent;
+    newp->level = oldparent->level + 1;
+    return 1;
+  }
+  return 0;
+}
+
+#if 0
+static struct PolygonEdge root;
+// A static variable to make things easy.
+
+void RebalanceAfterLeafAdd (struct PolygonEdge *n)
+{ // n is a PolygonEdge that has just been inserted and is now a leaf PolygonEdge.
+  n->level = 1;
+  n->left = NULL;
+  n->right = NULL;
+  for (n = n->parent; n != &root; n = n->parent) {
+    // At this point n->parent->level == n->level
+    if (n->level != (n->left ? n->left->level + 1 : 1)) {
+      // At this point the tree is correct, except (AA2) for n->parent
+      Skew (n);
+      // We handle it (a left add) by changing it into a right add using Skew
+      // If the original add was to the left side of a PolygonEdge that is on the
+      // right side of a horisontal link, n now points to the rights side
+      // of the second horisontal link, which is correct.
+      
+      // However if the original add was to the left of PolygonEdge with a horisontal
+      // link, we must get to the right side of the second link.
+      if (!n->right || n->level != n->right->level) n = n->parent;
+    }
+    if (!Split (n->parent)) break;
+  }
+}
+#endif
+
+void Delete (struct PolygonEdge *n)
+{ // If n is not a leaf, we first swap it out with the leaf PolygonEdge that just
+  // precedes it.
+  struct PolygonEdge *leaf = n;
+  
+  if (n->left) {
+    for (leaf = n->left; leaf->right; leaf = leaf->right) {}
+    // When we stop, left has no 'right' child so it cannot have a left one
+    #ifdef AATREE_NOREBALANCE
+    // Remove leaf:
+    if (leaf->parent->left == leaf) leaf->parent->left = leaf->left;
+    else leaf->parent->right = leaf->left;
+    if (leaf->left) leaf->left->parent = leaf->parent;
+    // Replace n with leaf:
+    leaf->parent = n->parent;
+    leaf->left = n->left;
+    leaf->right = n->right;
+    if (n->parent->left == n) n->parent->left = leaf;
+    else n->parent->right = leaf;
+    if (leaf->left) leaf->left->parent = leaf;
+    if (leaf->right) leaf->right->parent = leaf;
+    return;
+    #endif
+  }
+  #ifdef AATREE_NOREBALANCE
+  else {
+    if (n->parent->left == n) n->parent->left = n->right;
+    else n->parent->right = n->right;
+    if (n->right) n->right->parent = n->parent;
+    return;
+  }
+  #else
+  else if (n->right) leaf = n->right;
+  #endif
+
+  #ifndef AATREE_NOREBALANCE
+  struct PolygonEdge *tmp = leaf->parent == n ? leaf : leaf->parent;
+  #endif
+  if (leaf->parent->left == leaf) leaf->parent->left = NULL;
+  else leaf->parent->right = NULL;
+  
+  if (n != leaf) {
+    if (n->parent->left == n) n->parent->left = leaf;
+    else n->parent->right = leaf;
+    leaf->parent = n->parent;
+    if (n->left) n->left->parent = leaf;
+    leaf->left = n->left;
+    if (n->right) n->right->parent = leaf;
+    leaf->right = n->right;
+    leaf->level = n->level;
+  }
+  #ifndef AATREE_NOREBALANCE
+  // free (n);
+  while (tmp != &root) {
+    // One of tmp's childern had it's level reduced
+    if (tmp->level > (tmp->left ? tmp->left->level + 1 : 1)) { // AA2 failed
+      tmp->level--;
+      if (Split (tmp)) {
+        if (Split (tmp)) Skew (tmp->parent->parent);
+        break;
+      }
+      tmp = tmp->parent;
+    }
+    else if (tmp->level <= (tmp->right ? tmp->right->level + 1 : 1)) break;
+    else { // AA3 failed
+      Skew (tmp);
+      //if (tmp->right) tmp->right->level = tmp->right->left ? tmp->right->left->level + 1 : 1;
+      if (tmp->level > tmp->parent->level) {
+        Skew (tmp);
+        Split (tmp->parent->parent);
+        break;
+      }
+      tmp = tmp->parent->parent;
+    }
+  }
+  #endif
+}
+
+void Check (struct PolygonEdge *n)
+{
+  assert (!n->left || n->left->parent == n);
+  assert (!n->right || n->right->parent == n);
+//  assert (!Next (n) || n->data <= Next (n)->data);
+  assert (!n->parent || n->parent->level >= n->level);
+  assert (n->level == (n->left == NULL ? 1 : n->left->level + 1));
+  assert (n->level <= 1 || (n->right && n->level - n->right->level <= 1));
+  assert (!n->parent || !n->parent->parent ||
+          n->parent->parent->level > n->level);
+}
+
+void Add (struct PolygonEdge *n, struct PolygonEdge *root)
+{
+  struct PolygonEdge *s = root;
+  int lessThan = 1;
+  while (lessThan ? s->left : s->right) {
+    s = lessThan ? s->left : s->right;
+    lessThan = edgeCmp(n, s); //c.operator<(n, s);
+  }
+  if (lessThan) s->left = n;
+  else s->right = n;
+  n->parent = s;
+  #ifdef AATREE_NOREBALANCE
+  n->level = 1;
+  n->left = NULL;
+  n->right = NULL;
+  #else
+  RebalanceAfterLeafAdd (n);
+  #endif
+}
+//----------------------------[ End of AA tree ]----------------------------
+
+int ptSize = 0;
+void AddPolygon (vector<PolygonEdge> &d, FixedPoint *p, int cnt)
+{
+  int i, j, k, firstd = d.size();
+  ptSize = cnt;
+  for (j = cnt - 1; j > 0 && (p[j - 1].y == p[j].y || // p[j..cnt-1] becomes
+    (p[j - 1].y < p[j].y) == (p[j].y < p[0].y)); j--) {} // monotone
+  //if (j == 0) return; // Polygon has no height but it does not cause infinite loop
+  for (i = 0; i < j && (p[i].y == p[i + 1].y ||
+    (p[i].y < p[i + 1].y) == (p[j].y < p[0].y)); i++) {}
+  // Now p[cn-1],p[0..i] is the longest monotone sequence
+  d.resize (firstd + 2);
+  memset (&d[firstd], 0, sizeof (d[0]) * 2); // TODO: remove
+  d[firstd].delta = p[j].y < p[0].y ? 1 : -1;
+  d[firstd].continues = 1;
+  d[firstd + 1].delta = p[j].y < p[0].y ? 1 : -1;
+  d[firstd + 1].continues = 0;
+  d[firstd + !(p[j].y < p[0].y)].cnt = cnt - j;
+  d[firstd + (p[j].y < p[0].y)].cnt = i + 1;
+  d[firstd + !(p[j].y < p[0].y)].pt = p + (p[j].y < p[0].y ? j : cnt - 1);
+  d[firstd + (p[j].y < p[0].y)].pt = p + (p[j].y < p[0].y ? 0 : i);
+  //int lowest = j;
+  for (; i < j ; i = k) {
+    //if (p[lowest].y > p[i].y) lowest = i;
+    for (k = i + 1; k < j && (p[k].y == p[k + 1].y || // p[i..k] becomes
+        (p[k].y < p[k + 1].y) == (p[i].y < p[k].y)); k++) {} // monotone
+    d.push_back(PolygonEdge());
+    memset (&d.back(), 0, sizeof (d[0])); // TODO: remove
+    d[d.size() - 1].pt = p + (p[i].y < p[k].y ? i : k);
+    d[d.size() - 1].delta = p[i].y < p[k].y ? 1 : -1;
+    d[d.size() - 1].continues = 0;
+    d[d.size() - 1].cnt = k - i + 1;
+  }
+/*  GdkPoint *ll = &p[lowest], *lr = &p[lowest];
+  do {
+    if (--ll < p) ll = p + cnt - 1;
+  } while (ll->y <= p[lowest].y);
+  do {
+    if (++lr >= p + cnt) lr = p;
+  } while (lr->y <= p[lowest].y);*/
+  calcType area = p[cnt-1].x * (calcType) p[0].y - p[0].x * (calcType) p[cnt-1].y;
+  for (i = 0; i < cnt - 1; i++) area += p[i].x*(calcType)p[i+1].y-
+    p[i+1].x * (calcType) p[i].y;
+  for (i = firstd; i < (int) d.size(); i++) {
+    // This ll/lr inequality is a cross product that is true if the polygon
+    // was clockwise. AddInnerPoly() will just negate isLeft.
+    d[i].isLeft = (area < 0) == (d[i].delta == 1);
+  }
+}
+
+void AddClockwise (vector<PolygonEdge> &d, FixedPoint *p, int cnt)
+{
+  int i, j;
+  #if 0
+  for (i = 0; i < cnt; i++) __android_log_print (ANDROID_LOG_WARN, "Gosmore",
+    "pt[ptCnt].x = %d; pt[ptCnt++].y=%d;", p[i].x, p[i].y);
+  __android_log_print (ANDROID_LOG_WARN, "Gosmore", "AddClockwise(d,pt,ptCnt); ptCnt = 0;");
+  #endif
+  for (i = 0; i < cnt - 1 && p[i].y == p[0].y; i++) {}
+  int up = p[i].y > p[0].y;
+  for (i = 0; i < cnt - 1; i = j) {
+    d.push_back(PolygonEdge());
+    memset (&d.back(), 0, sizeof (d[0])); //TODO: remove
+    for (j = i; j + 1 < cnt &&
+      (up ? p[j + 1].y >= p[j].y : p[j + 1].y <= p[j].y); j++) {}
+    d[d.size() - 1].pt = up ? p + i : p + j;
+    d[d.size() - 1].delta = up ? 1 : -1;
+    d[d.size() - 1].isLeft = up;
+    d[d.size() - 1].cnt = j - i + 1;
+    d[d.size() - 1].continues = 0;
+    up = !up;
+  }
+}
+
+#ifdef ANDROID_NDK
+void Fill (vector<PolygonEdge> &d,int isSea)
+#else
+void Fill (vector<PolygonEdge> &d,int isSea, GdkWindow *w, GdkGC *gc)
+#endif
+{
+  //PolygonEdge **heap = (PolygonEdge **) malloc ((d.size() + 1) * sizeof (*heap));
+  vector<PolygonEdge*> heap;
+  heap.resize (d.size() + 1);
+  memset (&heap[0], 0, sizeof (heap[0]) * (d.size()+1)); // TODO: remove
+  // leave heap[0] open to make indexing easier
+  int i, h = 1, j, sea = 0, start = 1;
+  PolygonEdge dummy, left, right, root;
+  
+  root.left = NULL;
+  root.right = NULL;
+  root.level = 1000000;
+  root.parent = NULL;
+  
+/*  for (i = 0; i < d.size(); i++) {
+    for (j = 0; j + 1 < d[i].cnt; j++) assert (d[i].pt[j*d[i].delta].y <= d[i].pt[(j+1)*d[i].delta].y);
+    if (d[i].continues)                assert (d[i].pt[j*d[i].delta].y <= d[i+1].pt->y);
+  } // Make sure AddPolygon() and variants are correct */
+  dummy.opp = &dummy;
+  for (i = 0; i < (int) d.size(); i++) {
+    for (j = h++; j > 1 && heap[j / 2]->pt->y > d[i].pt->y; j /= 2) {
+      heap[j] = heap[j/2];
+    }
+    heap[j] = &d[i];
+    d[i].opp = NULL;
+    memcpy (&d[i].prev, d[i].pt, sizeof (d[i].prev)); // This is only
+    // to make the compare work.
+    if (d[i].continues) ++i; // Don't add the second part to the heap
+  }
+  //for (i = 2; i < h; i++) assert (heap[i]->pt->y >= heap[i/2]->pt->y);
+  left.prev.x = -6000*65536;
+  left.prev.y = 0;
+  left.opp = &dummy;
+  //h < 3 || edgeCmp (heap[1],
+  //                heap[h == 3 || heap[2]->pt->y < heap[3]->pt->y ? 2 : 3])
+  //          != !heap[1]->isLeft ? &dummy : &right;
+  left.pt = &left.prev;
+  left.isLeft = 1;
+  Add (&left, &root);
+  right.prev.x = 6000*65536;
+  right.prev.y = 0;
+  right.opp = &dummy; //left.opp == &dummy ? &dummy : &left;
+  right.pt = &right.prev;
+  right.isLeft = 0;
+  Add (&right, &root);
+  while (h > 1) {
+    PolygonEdge *head = heap[1];
+    //printf ("%p %3d\n", head->opp, head->pt->y);
+    if (!head->opp) { // Insert it
+      Add (head, &root);
+      head->opp = head->isLeft ? Next (head) : Prev (head);
+      if (head->opp == NULL || head->opp->isLeft == head->isLeft) {
+        head->opp = &dummy;
+      }
+    }
+    PolygonEdge *o = head->opp;
+    /* Now we render the trapezium between head->opp and head->opp->opp up
+       to head->pt->y */
+    if (o != &dummy && o->opp != &dummy) {
+      GdkPoint q[6];
+      #define CLAMPX(x) (short)((x) >= (1<<29) ? 8191 : (x) < -(1<<29) ? -8191 : (x) >> 16)
+      q[2].x = CLAMPX (o->opp->prev.x);
+      q[2].y = CLAMPX (o->opp->prev.y);
+      q[3].x = CLAMPX (o->prev.x);
+      q[3].y = CLAMPX (o->prev.y);
+      o->prev.x = o->pt->y <= o->prev.y ? o->pt->x
+        : o->prev.x + (o->pt->x - o->prev.x) *
+            calcType (head->pt->y - o->prev.y) / (o->pt->y - o->prev.y);
+      q[0].x = CLAMPX(o->prev.x);
+      o->prev.y = head->pt->y;
+      q[0].y = CLAMPX(o->prev.y);
+      o->opp->prev.x = o->opp->pt->y <= o->opp->prev.y ? o->opp->pt->x
+        : o->opp->prev.x + (o->opp->pt->x - o->opp->prev.x) *
+      calcType (head->pt->y - o->opp->prev.y) / (o->opp->pt->y - o->opp->prev.y);
+      q[1].x = CLAMPX (o->opp->prev.x);
+      o->opp->prev.y = head->pt->y;
+      q[1].y = q[0].y;
+    //if (o->opp->prev.y != o->prev.y && o->opp->prev.x < 30000 &&
+    //  o->opp->prev.x > -30000 && o->prev.x < 30000 && o->prev.x > -30000)
+    //  __android_log_print (ANDROID_LOG_WARN, "Gosmore", "Prev dif");
+      if ((isSea || (o->pt != &o->prev && o->opp->pt != &o->opp->prev)) &&
+          q[o->pt == &o->prev ? 2 : 3].y < q[0].y) {
+      // Frequently it happens that one of the triangles has 0 area because
+      // two of the points are equal. TODO: Filter them out.
+        #ifdef ANDROID_NDK
+        memcpy (&q[4], &q[0], sizeof (q[4]));
+        memcpy (&q[5], &q[2], sizeof (q[5]));
+        glVertexPointer (2, GL_SHORT, 0, q);
+        glDrawArrays (GL_TRIANGLES, 0, 6);
+        #else
+        //memcpy (&q[2], &o->prev, sizeof (q[2]));
+        //memcpy (&q[3], &o->opp->prev, sizeof (q[3]));
+        gdk_draw_polygon (w, gc, TRUE, q, 4);
+        #endif
+        if (q[0].x > 100 && q[1].x <= 100) sea = o->opp == &left;
+        if (q[0].x <= 100 && q[1].x < 100) sea = o->opp == &right;
+        if (q[1].x > 100 && q[0].x <= 100) sea = o == &left;
+        if (q[1].x <= 100 && q[0].x < 100) sea = o == &right;
+        
+        if (start) {
+          start = 0;
+          if (sea) {
+            q[2].x = -6000;
+            q[3].x = 6000;
+            q[4].x = 0;
+            q[4].y = -6000;
+            #ifdef ANDROID_NDK
+            glVertexPointer (2, GL_SHORT, 0, q + 2);
+            glDrawArrays (GL_TRIANGLES, 0, 3);
+            #else
+            //memcpy (&q[2], &o->prev, sizeof (q[2]));
+            //memcpy (&q[3], &o->opp->prev, sizeof (q[3]));
+            gdk_draw_polygon (w, gc, TRUE, q + 2, 3);
+            #endif
+          }
+        }
+      } // If the trapezium has a non-zero height
+    }
+    if (o != &dummy && o->opp != head) {
+      o->opp->opp = &dummy; // Complete the 'Add'
+      o->opp = head;
+    }
+
+    if (--head->cnt) head->pt += head->delta;
+    else if (head->continues) {
+      head->continues = head[1].continues;
+      head->cnt = head[1].cnt;
+      head->pt = head[1].pt;
+    }
+    else { // Remove it
+      head->opp->opp = &dummy;
+      PolygonEdge *n = head->isLeft ? Prev (head) : Next (head);
+      if (n && n->opp == &dummy) {
+        if (head->isLeft == n->isLeft && 
+          (head->opp->pt != &head->opp->prev || n->pt != &n->prev || sea)) {
+          n->opp = head->opp;
+          head->opp->opp = n;
+          n->prev.x += n->pt->y <= n->prev.y ? n->pt->x - n->prev.x :
+            (n->pt->x - n->prev.x) *
+            calcType(head->prev.y - n->prev.y) / (n->pt->y - n->prev.y);
+          n->prev.y = head->prev.y;
+        }
+        else {
+          // Either n is not a replacement for head because one of them is
+          // a left side and the other right side 
+          // OR
+          // heap->opp is either left or right and n is either left or right.
+          // and we recently drew all the way to the left or right ("sea").
+          n->opp = &dummy;
+          head->opp->opp = &dummy;
+        }
+      }
+      Delete (head);
+      head = heap[--h];
+    }
+    
+    for (j = 2; j < h; j *= 2) {
+      if (j + 1 < h && heap[j + 1]->pt->y < heap[j]->pt->y) j++;
+      if (heap[j]->pt->y >= head->pt->y) break;
+      heap[j / 2] = heap[j];
+    }
+    heap[j / 2] = head;
+    for (i = 2; i < h; i++) assert (heap[i]->pt->y >= heap[i/2]->pt->y);
+  } // While going through the edges
+  if (sea) { //left.opp == &right) {
+    GdkPoint end[3];
+    end[0].x = -6000;
+    end[0].y = max (left.prev.y, right.prev.y) >> 16;
+    end[1].x = 6000;
+    end[1].y = end[0].y;
+    end[2].x = 0; 
+    end[2].y = 6000;
+    #ifdef ANDROID_NDK
+    glVertexPointer (2, GL_SHORT, 0, end);
+    glDrawArrays (GL_TRIANGLES, 0, 3);
+    #else
+    gdk_draw_polygon (w, gc, TRUE, end, 3);
+    #endif
+  }
+  //free (heap);
+}
+#endif
diff --git a/jni/openglespolygon.h b/jni/openglespolygon.h
new file mode 100755
index 0000000..9a5abf4
--- /dev/null
+++ b/jni/openglespolygon.h
@@ -0,0 +1,42 @@
+#if !defined(OPENGLESPOLYGON_H) && !defined(HEADLESS)
+#define OPENGLESPOLYGON_H
+#include <vector>
+#if !defined(ANDROID_NDK) && !defined(NOGTK)
+#include <gdk/gdk.h> 
+#endif
+
+struct FixedPoint {
+  int x, y;
+};
+
+struct PolygonEdge {
+  int isLeft : 1;
+  int delta : 2; // Either -1 or 1
+  int continues : 1; // It's a polygon stored in an array and this edge wraps
+                     // over. We should continue at this+1 when cnt runs out.
+  int cnt : 20;
+  FixedPoint *pt, prev;
+  PolygonEdge *opp;
+/* I tried to make PolygonEdge a node in a tree by using a set<>. It failed
+   and I'm not sure how to fix it (add an iterator here ?).
+  set<PolygonEdge *, edgeCmp>::iterator itr;
+
+   So instead I copied and pasted my own AA tree code here:
+*/
+  PolygonEdge *parent, *left, *right;
+  int level;
+};
+
+#if defined(ANDROID_NDK) || defined(NOGTK)
+struct GdkPoint {
+  short x, y;
+};
+
+void Fill (std::vector<PolygonEdge> &d,int hasSea);
+#else
+void Fill (std::vector<PolygonEdge> &d,int hasSea, GdkWindow *w, GdkGC *gc);
+#endif
+void AddPolygon (std::vector<PolygonEdge> &d, FixedPoint *p, int cnt);
+void AddClockwise (std::vector<PolygonEdge> &d, FixedPoint *p, int cnt);
+
+#endif
diff --git a/resource.h b/jni/resource.h
similarity index 100%
rename from resource.h
rename to jni/resource.h
diff --git a/translations.c b/jni/translations.c
similarity index 100%
rename from translations.c
rename to jni/translations.c
diff --git a/proguard.cfg b/proguard.cfg
new file mode 100755
index 0000000..bf4ea78
--- /dev/null
+++ b/proguard.cfg
@@ -0,0 +1,48 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-assumenosideeffects class android.util.Log {
+    public static *** d(...);
+    public static *** v(...);
+}
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keep class org.osmu.gosmore.MapRenderer {
+    void drawTeks(java.lang.String,int,int,float,float);
+}
+
+-keep class org.osmu.gosmore.Search {
+    void searchResult(int,int,int,int,double,int,int,
+      java.lang.String,double,double,int);
+}
+
+-keepclasseswithmembernames class * {
+    native <methods>;
+}
+
+-keepclasseswithmembernames class * {
+    public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembernames class * {
+    public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+  public static final android.os.Parcelable$Creator *;
+}
diff --git a/res/drawable-hdpi/btn_square_overlay_normal.png b/res/drawable-hdpi/btn_square_overlay_normal.png
new file mode 100755
index 0000000..419ad52
Binary files /dev/null and b/res/drawable-hdpi/btn_square_overlay_normal.png differ
diff --git a/res/drawable-hdpi/btn_zoom_down_disabled.png b/res/drawable-hdpi/btn_zoom_down_disabled.png
new file mode 100755
index 0000000..6fc8d50
Binary files /dev/null and b/res/drawable-hdpi/btn_zoom_down_disabled.png differ
diff --git a/res/drawable-hdpi/btn_zoom_down_disabled_focused.png b/res/drawable-hdpi/btn_zoom_down_disabled_focused.png
new file mode 100755
index 0000000..12d2244
Binary files /dev/null and b/res/drawable-hdpi/btn_zoom_down_disabled_focused.png differ
diff --git a/res/drawable-hdpi/btn_zoom_down_normal.png b/res/drawable-hdpi/btn_zoom_down_normal.png
new file mode 100755
index 0000000..4105dd3
Binary files /dev/null and b/res/drawable-hdpi/btn_zoom_down_normal.png differ
diff --git a/res/drawable-hdpi/btn_zoom_down_pressed.png b/res/drawable-hdpi/btn_zoom_down_pressed.png
new file mode 100755
index 0000000..d109a4d
Binary files /dev/null and b/res/drawable-hdpi/btn_zoom_down_pressed.png differ
diff --git a/res/drawable-hdpi/btn_zoom_down_selected.png b/res/drawable-hdpi/btn_zoom_down_selected.png
new file mode 100755
index 0000000..ed9b858
Binary files /dev/null and b/res/drawable-hdpi/btn_zoom_down_selected.png differ
diff --git a/res/drawable-hdpi/btn_zoom_up_disabled.png b/res/drawable-hdpi/btn_zoom_up_disabled.png
new file mode 100755
index 0000000..2d144b9
Binary files /dev/null and b/res/drawable-hdpi/btn_zoom_up_disabled.png differ
diff --git a/res/drawable-hdpi/btn_zoom_up_disabled_focused.png b/res/drawable-hdpi/btn_zoom_up_disabled_focused.png
new file mode 100755
index 0000000..d4757e0
Binary files /dev/null and b/res/drawable-hdpi/btn_zoom_up_disabled_focused.png differ
diff --git a/res/drawable-hdpi/btn_zoom_up_normal.png b/res/drawable-hdpi/btn_zoom_up_normal.png
new file mode 100755
index 0000000..9cddba8
Binary files /dev/null and b/res/drawable-hdpi/btn_zoom_up_normal.png differ
diff --git a/res/drawable-hdpi/btn_zoom_up_pressed.png b/res/drawable-hdpi/btn_zoom_up_pressed.png
new file mode 100755
index 0000000..614e78f
Binary files /dev/null and b/res/drawable-hdpi/btn_zoom_up_pressed.png differ
diff --git a/res/drawable-hdpi/btn_zoom_up_selected.png b/res/drawable-hdpi/btn_zoom_up_selected.png
new file mode 100755
index 0000000..86b8ca2
Binary files /dev/null and b/res/drawable-hdpi/btn_zoom_up_selected.png differ
diff --git a/res/drawable-hdpi/ic_menu_play_clip.png b/res/drawable-hdpi/ic_menu_play_clip.png
new file mode 100755
index 0000000..06b6531
Binary files /dev/null and b/res/drawable-hdpi/ic_menu_play_clip.png differ
diff --git a/res/drawable-hdpi/icon.png b/res/drawable-hdpi/icon.png
new file mode 100755
index 0000000..0804f50
Binary files /dev/null and b/res/drawable-hdpi/icon.png differ
diff --git a/res/drawable-hdpi/stat_sys_upload_anim0.png b/res/drawable-hdpi/stat_sys_upload_anim0.png
new file mode 100755
index 0000000..96c333e
Binary files /dev/null and b/res/drawable-hdpi/stat_sys_upload_anim0.png differ
diff --git a/res/drawable-ldpi/icon.png b/res/drawable-ldpi/icon.png
new file mode 100755
index 0000000..c868645
Binary files /dev/null and b/res/drawable-ldpi/icon.png differ
diff --git a/res/drawable-mdpi/btn_square_overlay_normal.png b/res/drawable-mdpi/btn_square_overlay_normal.png
new file mode 100755
index 0000000..4844802
Binary files /dev/null and b/res/drawable-mdpi/btn_square_overlay_normal.png differ
diff --git a/res/drawable-mdpi/btn_zoom_down_disabled.png b/res/drawable-mdpi/btn_zoom_down_disabled.png
new file mode 100755
index 0000000..4e27dea
Binary files /dev/null and b/res/drawable-mdpi/btn_zoom_down_disabled.png differ
diff --git a/res/drawable-mdpi/btn_zoom_down_disabled_focused.png b/res/drawable-mdpi/btn_zoom_down_disabled_focused.png
new file mode 100755
index 0000000..2d416e0
Binary files /dev/null and b/res/drawable-mdpi/btn_zoom_down_disabled_focused.png differ
diff --git a/res/drawable-mdpi/btn_zoom_down_normal.png b/res/drawable-mdpi/btn_zoom_down_normal.png
new file mode 100755
index 0000000..b362a84
Binary files /dev/null and b/res/drawable-mdpi/btn_zoom_down_normal.png differ
diff --git a/res/drawable-mdpi/btn_zoom_down_pressed.png b/res/drawable-mdpi/btn_zoom_down_pressed.png
new file mode 100755
index 0000000..b2a2344
Binary files /dev/null and b/res/drawable-mdpi/btn_zoom_down_pressed.png differ
diff --git a/res/drawable-mdpi/btn_zoom_down_selected.png b/res/drawable-mdpi/btn_zoom_down_selected.png
new file mode 100755
index 0000000..2f694ff
Binary files /dev/null and b/res/drawable-mdpi/btn_zoom_down_selected.png differ
diff --git a/res/drawable-mdpi/btn_zoom_up_disabled.png b/res/drawable-mdpi/btn_zoom_up_disabled.png
new file mode 100755
index 0000000..7f54672
Binary files /dev/null and b/res/drawable-mdpi/btn_zoom_up_disabled.png differ
diff --git a/res/drawable-mdpi/btn_zoom_up_disabled_focused.png b/res/drawable-mdpi/btn_zoom_up_disabled_focused.png
new file mode 100755
index 0000000..25b14f8
Binary files /dev/null and b/res/drawable-mdpi/btn_zoom_up_disabled_focused.png differ
diff --git a/res/drawable-mdpi/btn_zoom_up_normal.png b/res/drawable-mdpi/btn_zoom_up_normal.png
new file mode 100755
index 0000000..7af5e0d
Binary files /dev/null and b/res/drawable-mdpi/btn_zoom_up_normal.png differ
diff --git a/res/drawable-mdpi/btn_zoom_up_pressed.png b/res/drawable-mdpi/btn_zoom_up_pressed.png
new file mode 100755
index 0000000..8cec199
Binary files /dev/null and b/res/drawable-mdpi/btn_zoom_up_pressed.png differ
diff --git a/res/drawable-mdpi/btn_zoom_up_selected.png b/res/drawable-mdpi/btn_zoom_up_selected.png
new file mode 100755
index 0000000..0bf543e
Binary files /dev/null and b/res/drawable-mdpi/btn_zoom_up_selected.png differ
diff --git a/res/drawable-mdpi/ic_menu_play_clip.png b/res/drawable-mdpi/ic_menu_play_clip.png
new file mode 100755
index 0000000..a8151fc
Binary files /dev/null and b/res/drawable-mdpi/ic_menu_play_clip.png differ
diff --git a/res/drawable-mdpi/icon.png b/res/drawable-mdpi/icon.png
new file mode 100755
index 0000000..4118dbb
Binary files /dev/null and b/res/drawable-mdpi/icon.png differ
diff --git a/res/drawable-mdpi/stat_sys_download_anim0.png b/res/drawable-mdpi/stat_sys_download_anim0.png
new file mode 100755
index 0000000..44576fd
Binary files /dev/null and b/res/drawable-mdpi/stat_sys_download_anim0.png differ
diff --git a/res/drawable/mappaint.png b/res/drawable/mappaint.png
new file mode 100755
index 0000000..d3d81e5
Binary files /dev/null and b/res/drawable/mappaint.png differ
diff --git a/res/layout/download_progress.xml b/res/layout/download_progress.xml
new file mode 100755
index 0000000..5587011
--- /dev/null
+++ b/res/layout/download_progress.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+android:layout_width="fill_parent" android:layout_height="fill_parent"
+android:padding="5dp">
+<ImageView android:id="@+id/status_icon"
+android:layout_width="wrap_content" android:layout_height="fill_parent"
+android:layout_alignParentLeft="true" />
+
+<RelativeLayout android:layout_width="fill_parent"
+android:layout_height="fill_parent" android:layout_toRightOf="@id/status_icon">
+
+<TextView android:id="@+id/status_text" android:layout_width="fill_parent"
+android:layout_height="wrap_content" android:layout_alignParentTop="true" />
+<ProgressBar android:id="@+id/status_progress"
+android:layout_width="fill_parent" android:layout_height="wrap_content"
+android:layout_below="@id/status_text"
+android:progressDrawable="@android:drawable/progress_horizontal"
+android:indeterminate="false" android:indeterminateOnly="false" />
+
+
+</RelativeLayout>
+
+</RelativeLayout>
+
diff --git a/res/layout/map_help.xml b/res/layout/map_help.xml
new file mode 100755
index 0000000..f677469
--- /dev/null
+++ b/res/layout/map_help.xml
@@ -0,0 +1,107 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:background="#ffffff"
+        android:gravity="center_vertical|left"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+    <!-- Here is where we put the SurfaceView, in a frame so that we can
+         stack other views on top of it. -->
+<!--     <FrameLayout
+            android:layout_width="fill_parent"
+            android:layout_height="0px"
+            android:layout_weight="1"> -->
+   <TextView  android:layout_width="fill_parent"
+        android:textSize="20sp"
+        android:textColor="#000000"
+        android:text="Icons used in Gosmore:"
+        android:layout_height="0dip" android:layout_weight="1"
+        android:gravity="center_horizontal|center_horizontal"/>
+        <LinearLayout android:orientation="horizontal"
+        android:gravity="center"
+                android:layout_width="wrap_content"
+        android:layout_height="0dip" android:layout_weight="1">
+
+            <ImageView android:id="@+id/map_search"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:clickable="false"
+                    android:layout_alignParentRight="true"
+                    android:layout_alignParentTop="true"
+                    android:src="@android:drawable/ic_menu_search"/>
+   <TextView  android:layout_width="wrap_content"
+        android:textSize="20sp"
+        android:textColor="#000000"
+        android:layout_height="fill_parent"
+        android:text="Search"
+        android:gravity="left|center_vertical"/>
+</LinearLayout>                    
+        <LinearLayout android:orientation="horizontal"
+        android:gravity="center"
+        android:layout_height="0dip" android:layout_weight="1"
+                android:layout_width="wrap_content">
+            <ImageView android:id="@+id/map_recent"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:clickable="false"
+                    android:layout_alignParentLeft="true"
+                    android:layout_alignParentTop="true"
+                    android:src="@android:drawable/ic_menu_recent_history"/>
+   <TextView  android:layout_width="wrap_content"
+        android:textSize="20sp"
+        android:textColor="#000000"
+        android:layout_height="fill_parent"
+        android:text="Recent Searches"
+        android:gravity="left|center_vertical"/>
+</LinearLayout>                    
+        <LinearLayout android:orientation="horizontal"
+        android:gravity="center"
+        android:layout_height="0dip" android:layout_weight="1"
+                android:layout_width="wrap_content">
+                    
+            <ImageView android:id="@+id/mylocation"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:clickable="false"
+                    android:layout_alignParentLeft="true"
+                    android:layout_alignParentBottom="true"
+                    android:src="@android:drawable/ic_menu_mylocation"/>
+   <TextView  android:layout_width="wrap_content"
+        android:textSize="20sp"
+        android:textColor="#000000"
+        android:layout_height="fill_parent"
+        android:text="My Location / Enable GPS"
+        android:gravity="center_vertical"/>
+</LinearLayout>                    
+        <LinearLayout android:orientation="horizontal"
+        android:layout_height="0dip" android:layout_weight="1"
+        android:gravity="center"
+                android:layout_width="wrap_content">
+
+            <ImageView android:id="@+id/zoom_out"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:clickable="false"
+                    android:src="@drawable/btn_zoom_down_normal"/>
+                    <!-- android:visibility="gone" -->
+            
+            <ImageView android:id="@+id/zoom_in"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:clickable="false"
+                    android:src="@drawable/btn_zoom_up_normal"/>
+   <TextView  android:layout_width="wrap_content"
+        android:textSize="20sp"
+        android:textColor="#000000"
+        android:layout_height="fill_parent"
+        android:text="Zoom"
+        android:gravity="center"/>
+</LinearLayout>                    
+                    
+   <TextView  android:layout_width="fill_parent"
+        android:layout_height="0dip" android:layout_weight="1"
+        android:textSize="20sp"
+        android:textColor="#000000"
+        android:text="Now press 'Back'"
+        android:gravity="center_horizontal|center_horizontal"/>
+</LinearLayout>
diff --git a/res/layout/map_view.xml b/res/layout/map_view.xml
new file mode 100755
index 0000000..cd34dae
--- /dev/null
+++ b/res/layout/map_view.xml
@@ -0,0 +1,67 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+    <!-- Here is where we put the SurfaceView, in a frame so that we can
+         stack other views on top of it. -->
+<!--     <FrameLayout
+            android:layout_width="fill_parent"
+            android:layout_height="0px"
+            android:layout_weight="1"> -->
+<RelativeLayout 
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+        <org.osmu.gosmore.MapView android:id="@+id/mapview"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent" />
+
+            <ImageView android:id="@+id/map_search"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:clickable="true"
+                    android:layout_alignParentRight="true"
+                    android:layout_alignParentTop="true"
+                    android:src="@android:drawable/ic_menu_search"/>
+                    
+            <ImageView android:id="@+id/map_recent"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:clickable="true"
+                    android:layout_alignParentLeft="true"
+                    android:layout_alignParentTop="true"
+                    android:src="@android:drawable/ic_menu_recent_history"/>
+                    
+            <ImageView android:id="@+id/mylocation"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:clickable="true"
+                    android:layout_alignParentLeft="true"
+                    android:layout_alignParentBottom="true"
+                    android:src="@android:drawable/ic_menu_mylocation"/>
+        <LinearLayout android:id="@+id/hidecontainer"
+                android:orientation="horizontal"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentRight="true"
+                android:layout_alignParentBottom="true">
+
+            <ImageView android:id="@+id/zoom_out"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:clickable="true"
+                    android:src="@drawable/btn_zoom_down_normal"/>
+                    <!-- android:visibility="gone" -->
+            
+            <ImageView android:id="@+id/zoom_in"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:clickable="true"
+                    android:src="@drawable/btn_zoom_up_normal"/>
+                    
+        </LinearLayout>
+        
+    </RelativeLayout>
+            
+</LinearLayout>
diff --git a/res/layout/old_main.xml b/res/layout/old_main.xml
new file mode 100755
index 0000000..329c046
--- /dev/null
+++ b/res/layout/old_main.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    >
+        
+        <Button android:id="@+id/button_search"
+            android:text="Search" android:textSize="30sp"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent" />
+
+        <Button android:id="@+id/button_map"
+            android:text="Map" android:textSize="30sp"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent" />
+
+        <Button android:id="@+id/button_configure"
+            android:text="Configure" android:textSize="30sp"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent" />
+    
+        <Button android:id="@+id/button_update"
+            android:text="Update" android:textSize="30sp"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent" android:enabled="false"/>
+    
+</LinearLayout>
diff --git a/res/layout/search.xml b/res/layout/search.xml
new file mode 100755
index 0000000..e10c8a3
--- /dev/null
+++ b/res/layout/search.xml
@@ -0,0 +1,29 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:orientation="vertical">
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+    <ImageView android:id="@+id/spacer"
+        android:layout_width="37dip"
+        android:layout_height="48dip" />
+ 
+    <EditText android:id="@+id/search_query"
+       android:singleLine="true"
+       android:layout_width="fill_parent"
+       android:layout_height="wrap_content"
+       android:imeOptions="actionDone"
+       android:autoText="false"
+       android:hint="Search"/>
+</LinearLayout>
+
+    <ListView android:id="@android:id/list"
+        android:layout_width="fill_parent" 
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        android:drawSelectorOnTop="false"/>
+
+
+</LinearLayout>
diff --git a/res/layout/search_result.xml b/res/layout/search_result.xml
new file mode 100755
index 0000000..f37e78e
--- /dev/null
+++ b/res/layout/search_result.xml
@@ -0,0 +1,30 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+
+    <ImageView android:id="@+id/result_icon"
+        android:layout_alignParentLeft="true"
+        android:scaleType="center"
+        android:layout_width="48dip"
+        android:layout_height="48dip" />
+
+<!--         android:layout_weight="1.0" 
+        android:layout_width="0dip"
+        android:layout_gravity="left"
+-->
+
+    <TextView android:id="@+id/distance"
+        android:layout_alignParentRight="true"
+        android:gravity="center_vertical|right"
+        android:textSize="18sp"
+        android:layout_width="wrap_content"
+        android:layout_height="fill_parent" />
+
+    <TextView android:id="@+id/result_text"
+        android:layout_toRightOf="@+id/result_icon"
+        android:gravity="center_vertical|left"
+        android:textSize="18sp"
+        android:layout_toLeftOf="@+id/distance"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent" />
+</RelativeLayout>
diff --git a/res/layout/update.xml b/res/layout/update.xml
new file mode 100755
index 0000000..5514fb0
--- /dev/null
+++ b/res/layout/update.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+
+    <ProgressBar android:id="@+id/update_progress"
+        style="?android:attr/progressBarStyleHorizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:max="100"
+        android:progress="0"
+        android:secondaryProgress="0" />
+
+    <!-- <TextView android:id="@+id/update_description"
+        android:layout_width="wrap_content"
+         android:textSize="30sp"
+        android:layout_height="wrap_content"
+        android:text="Downloading the default overview map"
+        android:layout_gravity="center_horizontal"/> -->
+    <TextView android:id="@+id/update_msg"
+        android:layout_width="wrap_content"
+         android:textSize="30sp"
+        android:layout_height="wrap_content"
+        android:text="" android:layout_gravity="center_horizontal"/>        
+    <Button android:id="@+id/cancel_update"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="30sp"
+        android:text="Cancel" android:layout_gravity="center_horizontal"/>
+</LinearLayout>
diff --git a/res/menu/map.xml b/res/menu/map.xml
new file mode 100755
index 0000000..d36fe2a
--- /dev/null
+++ b/res/menu/map.xml
@@ -0,0 +1,19 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/start_route"
+        android:title="Start Route"
+        android:icon="@drawable/ic_menu_play_clip" />
+
+    <item android:id="@+id/end_route"
+        android:title="End Route"
+        android:icon="@drawable/btn_square_overlay_normal" />
+
+    <item android:id="@+id/preferences"
+        android:title="Settings"
+        android:icon="@android:drawable/ic_menu_preferences" />
+    <item android:id="@+id/update"
+        android:title="Update"
+        android:icon="@drawable/stat_sys_download_anim0" />
+    <item android:id="@+id/about"
+        android:title="About"
+        android:icon="@android:drawable/ic_dialog_info" />
+</menu>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
new file mode 100755
index 0000000..1ea8458
--- /dev/null
+++ b/res/values/arrays.xml
@@ -0,0 +1,38 @@
+<resources>
+<string-array name="vehicle_entries">
+        <item>Motorcar</item>
+        <item>Bicycle</item>
+        <item>Pedestrian</item>
+        <item>Goods Vehicle</item>
+        <item>Heavy Goods Vehicle</item>
+        <item>Horse</item>
+        <item>Motorcycle</item>
+        <item>Bus</item>
+        <item>Moped</item>
+        <item>Mofa</item>
+        <item>Motorboat</item>
+        <item>Boat</item>
+        </string-array>
+        <string-array name="vehicle_values">
+        <item>12</item>
+        <item>13</item>
+        <item>14</item>
+        <item>15</item>
+        <item>16</item>
+        <item>17</item>
+        <item>18</item>
+        <item>19</item>
+        <item>20</item>
+        <item>21</item>
+        <item>22</item>
+        <item>23</item>
+        </string-array>
+        <string-array name="tts_entries">
+        <item>None / Disabled</item>
+        <item>English</item>
+        </string-array>
+        <string-array name="tts_values">
+        <item>0</item>
+        <item>1</item>
+        </string-array>
+</resources>  
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100755
index 0000000..e8c943c
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!--    <string name="hello">Hello World, Gosmore!</string> -->
+    <string name="app_name">Gosmore</string>
+    <string name="fastest">Fastest Route</string>
+    <string name="summary_fastest">Not the shortest</string>
+    <string name="north2d">Orient Northwards in 2D</string>
+    <string name="summary_north2d">Don\'t use the compass in 2D</string>
+    <string name="vehicle">Vehicle</string>
+    <string name="summary_vehicle">Vehicle / Transport mode</string>
+    <string name="tts">Voice Language</string>
+    <string name="summary_tts">Text to Speech instructions</string>
+    <string name="routing_progress">Calculating Route</string>
+    <string name="cancel">Cancel</string> <!-- Routing and no map dialogs -->
+    <string name="ok">OK</string> <!-- About and no map dialogs -->
+    <string name="about_title">About</string>
+    <string name="about_msg">
+        Copyright (C) 2011 Nic Roets and Gosmore contributors. All rights reserved.\n
+        THIS SOFTWARE IS PROVIDED BY NIC ROETS ``AS IS\'\' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NIC ROETS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n
+                
+   Some of the icons are copyright (c) 2005-2008, The Android Open Source Project\n
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.\n
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.\n\n
+        
+        Some of the data bundled with or downloaded by this application fall
+        under the following copyright. When the application interprets this data,
+        it does not affects it\'s copyright, only the copyright of the output.\n\n
+        Map data (C) OpenStreetMap contributors CC-BY-SA\n
+        http://creativecommons.org/licenses/by-sa/2.0/\n\n
+        Map styles and icons (C) JOSM and Gosmore contributors under the GNU
+        General Public License version 2 or later\n\n
+        City names and locations in default map (C)
+        Geonames.org contributors CC-BY 3.0\n\n
+    </string>
+    <string name="no_location_title">No location specified</string>
+    <string name="no_location_msg">
+    To find your location tap the location button.\n\n
+    To find a city, tap the search button and enter the first few letters.</string>
+    <string name="first_map_title">Location acquired</string>
+    <string name="first_map_msg">Download the map for your area ?</string>
+    <string name="no_sdcard_title">No SD Card</string>
+    <string name="no_sdcard_msg">The external storage is not mounted.</string>
+</resources>
diff --git a/src/org/osmu/gosmore/Gosmore.java b/src/org/osmu/gosmore/Gosmore.java
new file mode 100755
index 0000000..295ac3a
--- /dev/null
+++ b/src/org/osmu/gosmore/Gosmore.java
@@ -0,0 +1,83 @@
+package org.osmu.gosmore;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+
+import android.app.Application;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Environment;
+import android.util.Log;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+public class Gosmore extends Application {
+    public Bitmap icons;
+    public class Settings implements Serializable {
+    	static final long serialVersionUID = 6618718669L;
+    	ArrayList<Place> recent;
+    	String search;
+        Place searchResult; // This is where the app stores the current place
+    }
+    public Settings s;
+    public int updateProgress = -1;
+    public String updateMsg;
+    public boolean cancelUpdate = true;
+    public ProgressBar updateBar;
+    public TextView updateMsgView;
+    public Button updateCancel;
+    static {
+        System.loadLibrary("gosmore");
+    }
+    @Override 
+    public void onCreate() {
+    	File f = new File(Environment.getExternalStorageDirectory(), "/gosmore/icons.png");
+    	InputStream is;
+    	try {
+    		is = new FileInputStream(f);
+    	} catch (FileNotFoundException e) {
+           is = getApplicationContext().getResources().openRawResource(R.drawable.mappaint);
+    	}
+        try {
+            icons = BitmapFactory.decodeStream(is);
+        } finally {
+            try {
+                is.close();
+            } catch(IOException e) {
+            	Log.w ("Gosmore", "Cannot read icons.png");
+                // Ignore.
+            }
+        } 
+   		try {
+   			FileInputStream fis = openFileInput ("settings");
+   			ObjectInputStream in = new ObjectInputStream (fis);
+   			try {
+   				s = new Settings();
+   				s.recent = (ArrayList<Place>) in.readObject();
+   				s.search = (String) in.readObject();
+   				s.searchResult = (Place) in.readObject();
+   			}
+    		catch (ClassNotFoundException ex) {Log.w("Gosmore", "Settings file is corrupt");}
+   			in.close();
+   		} catch (IOException ex) {}//Log.d("gosmore", "Settings file not found");}
+   		  finally {
+   			if (s == null) {
+   				s = new Settings();
+   				s.searchResult = new Place();
+   				s.searchResult.lat = 0; // Set up reasonable defaults
+   				s.searchResult.lon = 0;
+   				s.searchResult.zoom = 1000000;
+   				s.searchResult.dir = 0;
+   				s.recent = new ArrayList<Place> ();
+   			}
+   		}
+    }
+}
+  
\ No newline at end of file
diff --git a/src/org/osmu/gosmore/MapActivity.java b/src/org/osmu/gosmore/MapActivity.java
new file mode 100755
index 0000000..0f185db
--- /dev/null
+++ b/src/org/osmu/gosmore/MapActivity.java
@@ -0,0 +1,726 @@
+package org.osmu.gosmore;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Locale;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.opengles.GL11;
+import javax.microedition.khronos.opengles.GL11Ext;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.hardware.GeomagneticField;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLUtils;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.SystemClock;
+import android.preference.PreferenceManager;
+import android.speech.tts.TextToSpeech;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.widget.ImageView;
+  
+public class MapActivity extends Activity implements TextToSpeech.OnInitListener {
+	private MapView mGLView;
+    private native int changePak (String sd, int lat, int lon);
+    public int pakType = 0; // This is really just a boolean
+    @Override  
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        requestWindowFeature(Window.FEATURE_PROGRESS);
+        /*// Uncomment for full screen
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+            WindowManager.LayoutParams.FLAG_FULLSCREEN);*/
+        if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) &&
+        	!Environment.MEDIA_MOUNTED_READ_ONLY.equals(Environment.getExternalStorageState())) {
+        	Log.d("Gosmore", "("+Environment.getExternalStorageState() + " " + Environment.MEDIA_MOUNTED+")"+
+        			(Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED));
+        	showDialog (5);
+        }
+        else {
+        File sd = new File (Environment.getExternalStorageDirectory(), "gosmore");
+        sd.mkdir (); 
+        if ((pakType = changePak (sd.getAbsolutePath(), 0, 0)) == 0) {
+          	Intent intent = new Intent (MapActivity.this, Update.class);
+      		startActivity(intent);
+            setContentView(R.layout.map_help);
+      		//finish(); 
+        }  
+        else if (false) { // Set this to see if things are faster with ImageViews
+            // Fixme and uncomment mGLView = new MapView(this);
+            setContentView(mGLView);
+        }  
+        else { 
+          setContentView(R.layout.map_view);
+          mGLView = (MapView) findViewById(R.id.mapview);
+          mGLView.activity = this; // So that the view can show a dialog
+          //final MapRenderer mr = mGLView.mRenderer;
+          ImageView.OnTouchListener otl = new ImageView.OnTouchListener() {
+        	  public boolean onTouch (View v, MotionEvent m) {
+        		  if (m.getAction() == MotionEvent.ACTION_DOWN) {
+        			  mGLView.requestRender ();
+        			  mGLView.mRenderer.zExp = v.getId() == 
+        				  R.id.zoom_out ? 0.001f : -0.001f;
+        			  mGLView.mRenderer.zTime = SystemClock.uptimeMillis()-50;
+        		  } 
+        		  if (m.getAction() == MotionEvent.ACTION_UP) {
+        			  long now = SystemClock.uptimeMillis();
+        			  mGLView.mRenderer.p.zoom = (int)(mGLView.mRenderer.p.zoom * Math.exp (mGLView.mRenderer.zExp * (now - mGLView.mRenderer.zTime)));
+        			  mGLView.mRenderer.zTime = 0;
+        		  }
+        	      return false;
+        	  }
+          };  
+          ImageView oImageView = (ImageView) findViewById (R.id.zoom_out);
+          oImageView.setOnTouchListener(otl);
+          ImageView iImageView = (ImageView) findViewById (R.id.zoom_in);
+          iImageView.setOnTouchListener(otl);
+          ImageView mImageView = (ImageView) findViewById (R.id.mylocation);
+          mImageView.setOnClickListener(new ImageView.OnClickListener() {
+        	  public void onClick (View v) {    
+        		  mGLView.mRenderer.follow = true;
+       	          mGLView.lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 10f, mGLView);
+       	          mGLView.mSensorManager.registerListener(mGLView.magListener,
+       	        		mGLView.mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
+       	        		SensorManager.SENSOR_DELAY_NORMAL);
+       	          mGLView.mSensorManager.registerListener(mGLView.accListener,
+       	        		mGLView.mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
+       	        		SensorManager.SENSOR_DELAY_UI);
+        	  }
+          });
+          ImageView sImageView = (ImageView) findViewById (R.id.map_search);
+          sImageView.setOnClickListener(new ImageView.OnClickListener() {
+        	  public void onClick (View v) {
+        		  Intent sintent = new Intent (MapActivity.this, Search.class);      
+        		  startActivity(sintent);
+        	  }
+          });
+          ImageView rImageView = (ImageView) findViewById (R.id.map_recent);
+          rImageView.setOnClickListener(new ImageView.OnClickListener() {
+        	  public void onClick (View v) {
+                  Intent intent = new Intent (MapActivity.this, Recent.class);      
+                  startActivity(intent);
+        	  }
+          });
+          mGLView.mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
+          mGLView.lm = (LocationManager) getSystemService(LOCATION_SERVICE);
+          SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+          if (!prefs.getString ("vehicle", "0").equals("0")) {
+        	  mGLView.mRenderer.mTts = new TextToSpeech(this, this);
+          }
+        }     
+        } // External storage is mounted
+        //mGLView.setDebugFlags (GLSurfaceView.DEBUG_CHECK_GL_ERROR );
+    }
+    @Override 
+    public boolean onCreateOptionsMenu(Menu menu) {
+    	MenuInflater inf = getMenuInflater();
+    	inf.inflate(R.menu.map, (Menu)menu);
+    	return true;
+    } 
+    @Override 
+    public Dialog onCreateDialog(int id) {
+    	if (id == 1) {
+    		mGLView.mRenderer.rProgress = new ProgressDialog(this);
+    		//mGLView.mRenderer.rProgress.setIcon(R.drawable.alert_dialog_icon);
+    		mGLView.mRenderer.rProgress.setTitle(R.string.routing_progress);
+    		mGLView.mRenderer.rProgress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+    		//mGLView.mRenderer.rProgress.setMax(MAX_PROGRESS);
+    		mGLView.mRenderer.rProgress.setButton(getText(R.string.cancel), new DialogInterface.OnClickListener() {
+    			public void onClick(DialogInterface dialog, int whichButton) {
+    				mGLView.mRenderer.route = false;
+    			}
+    		});
+        	return mGLView.mRenderer.rProgress;
+    	}
+    	else if (id == 2) {
+    		return new AlertDialog.Builder(this)
+            //.setIcon(R.drawable.alert_dialog_icon)
+            .setTitle(R.string.about_title)
+            .setMessage(R.string.about_msg)
+            .setPositiveButton(R.string.ok, null)
+            .create ();
+    	}
+    	else if (id == 3) {
+    		return new AlertDialog.Builder(this)
+            //.setIcon(R.drawable.alert_dialog_icon)
+            .setTitle(R.string.no_location_title)
+            .setMessage(R.string.no_location_msg)
+            .setPositiveButton(R.string.ok, null)
+            .create (); 
+    	}
+    	else if (id == 4) {
+    		return new AlertDialog.Builder(this)
+            //.setIcon(R.drawable.alert_dialog_icon)
+            .setTitle(R.string.first_map_title)
+            .setMessage(R.string.first_map_msg)
+            .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
+                public void onClick(DialogInterface dialog, int whichButton) {
+                	Intent intent = new Intent (MapActivity.this, Update.class);      
+          		  	startActivity(intent);
+                }
+            })
+            .setNegativeButton(R.string.cancel, null)
+            .create ();
+    	}
+    	else if (id == 5) {
+    		return new AlertDialog.Builder(this)
+            //.setIcon(R.drawable.alert_dialog_icon)
+            .setTitle(R.string.no_sdcard_title)
+            .setMessage(R.string.no_sdcard_msg)
+            .setPositiveButton(R.string.ok, null)
+            .create (); 
+    	}
+    	return null;
+    }
+    @Override 
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.start_route) {
+        	mGLView.mRenderer.startR = true;
+        	mGLView.requestRender ();
+        } 
+        else if (item.getItemId() == R.id.end_route) {
+        	showDialog(1);
+    		mGLView.mRenderer.route = true;
+    		mGLView.requestRender();
+        }
+        else if (item.getItemId() == R.id.preferences) {
+        	Intent sintent = new Intent (MapActivity.this, Preferences.class);      
+  		  	startActivity(sintent);
+        }
+        else if (item.getItemId() == R.id.update) {
+        	Intent sintent = new Intent (MapActivity.this, Update.class);      
+  		  	startActivity(sintent);
+        }
+        else if (item.getItemId() == R.id.about) {
+        	showDialog(2);
+        }
+        else return false;
+        return true;
+    }
+
+    @Override
+    public boolean onSearchRequested() {
+		  Intent sintent = new Intent (MapActivity.this, Search.class);      
+		  startActivity(sintent);
+		  return false;
+    }
+    
+    @Override 
+    protected void onPause() {
+        super.onPause();
+        Gosmore g = (Gosmore)getApplicationContext();
+   		try {
+   			FileOutputStream fos = openFileOutput ("settings", Context.MODE_PRIVATE);
+   			ObjectOutputStream out = new ObjectOutputStream (fos);
+   			out.writeObject(g.s.recent); // Can't serialize a Setting
+   			out.writeObject(g.s.search); // for some unknown reason.
+   			out.writeObject(g.s.searchResult);
+   			out.close();
+   		} catch (IOException ex) { Log.w ("Gosmore", "Cannot write settings");}
+   		if (mGLView != null && mGLView.mRenderer.follow) {
+   			mGLView.mRenderer.follow = false;
+   			mGLView.lm.removeUpdates(mGLView);
+   			mGLView.mSensorManager.unregisterListener (mGLView.magListener);
+   			mGLView.mSensorManager.unregisterListener (mGLView.accListener);
+   		}
+    }
+
+    @Override
+    protected void onResume()
+    {
+        super.onResume();
+        // Don't resume tracking automatically.
+    }
+    @Override
+    protected void onDestroy()
+    {
+    	if (mGLView != null && mGLView.mRenderer.mTts != null) {
+    		mGLView.mRenderer.mTts.stop();
+    		mGLView.mRenderer.mTts.shutdown();
+        }
+        super.onDestroy();
+    }
+    public void onInit(int status) {
+    	if (status == TextToSpeech.SUCCESS) {
+    		int result = mGLView.mRenderer.mTts.setLanguage(Locale.US);
+    		mGLView.mRenderer.tts = result != TextToSpeech.LANG_MISSING_DATA &&
+                result != TextToSpeech.LANG_NOT_SUPPORTED;
+    	}
+    }
+}
+
+class MapView extends GLSurfaceView implements LocationListener {
+	public LocationManager lm;
+	public SensorManager mSensorManager;
+	public MapActivity activity;
+    // ---- Location Listener methods ----
+    public void onLocationChanged(Location location) {
+    	mRenderer.lonSum += location.getLongitude();
+    	mRenderer.latSum += location.getLatitude();
+    	mRenderer.latLonCnt++;
+    	
+    	mRenderer.p.lat = location.getLatitude();
+    	mRenderer.declination =
+    		 (int)(new GeomagneticField((float)location.getLatitude(),
+    	  (float)location.getLongitude(),(float)location.getAltitude(),
+    	  /*time:*/1300000000000L)).getDeclination();
+    	mRenderer.bearing = location.getBearing();
+    	mRenderer.speed = location.getSpeed();
+    	mRenderer.doNavigate = true;
+    	if (Math.abs (mRenderer.p.lon - mRenderer.lonSum / mRenderer.latLonCnt) * 2 +
+    		Math.abs (mRenderer.p.lat - mRenderer.latSum / mRenderer.latLonCnt)
+    		> .000164 / mRenderer.latLonCnt + 0.00004) {
+    		mRenderer.p.lon = mRenderer.lonSum / mRenderer.latLonCnt;
+    		mRenderer.p.lat = mRenderer.latSum / mRenderer.latLonCnt;
+    		mRenderer.latLonCnt = 0;
+    		mRenderer.lonSum = 0;
+    		mRenderer.latSum = 0;
+        	requestRender ();
+    	}
+    }
+    public void onProviderDisabled(String provider) {}
+    public void onProviderEnabled(String provider) {}
+    public void onStatusChanged(String provider, int status, Bundle extras) {}
+    // ---- Location Listener methods ----
+    
+    //public native void setLocation (double lon, double lat);
+
+    public MapView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mRenderer = new MapRenderer(context);
+    	mRenderer.mIcons = ((Gosmore)context.getApplicationContext()).icons;
+        mRenderer.p = ((Gosmore)context.getApplicationContext()).s.searchResult;
+        mRenderer.mapView = this;
+        setRenderer(mRenderer);
+        setRenderMode (RENDERMODE_WHEN_DIRTY);
+    }
+    private float mPreviousX, mPreviousY, prevX2, prevY2;
+
+    @Override public boolean onTrackballEvent(MotionEvent e) {
+        mRenderer.mPixelX += e.getX() * 5.0 / 320;
+        mRenderer.mPixelY += e.getY() * 5.0 / 320;
+        requestRender();
+        if (mRenderer.follow) {
+        	mRenderer.follow = false;
+        	lm.removeUpdates(this);
+            mSensorManager.unregisterListener (magListener);
+            mSensorManager.unregisterListener (accListener);
+        }
+        return true;
+    }
+    private static Method getPointerCount, getPointerId, getX, getY;
+    static {
+    	try {
+    		getPointerCount = MotionEvent.class.getMethod("getPointerCount",
+    				new Class[] {});
+    		getPointerId = MotionEvent.class.getMethod("getPointerId",
+    				new Class[] { int.class });
+    		getX = MotionEvent.class.getMethod("getX",
+    				new Class[] { int.class });
+    		getY = MotionEvent.class.getMethod("getY",
+    				new Class[] { int.class });
+    	} catch (NoSuchMethodException nsme) {}
+    }
+     
+    @Override public boolean onTouchEvent(MotionEvent e) {
+    	if (true) {//getPointerCount == null) {
+        float x = e.getX();
+        float y = e.getY();
+        switch (e.getAction()) {
+        case MotionEvent.ACTION_MOVE:
+            mRenderer.mPixelX += (int)(x - mPreviousX);
+            mRenderer.mPixelY += (int)(y - mPreviousY);
+            if (mRenderer.follow) {
+            	mRenderer.follow = false;
+            	lm.removeUpdates(this);
+                mSensorManager.unregisterListener (magListener);
+                mSensorManager.unregisterListener (accListener);
+            }
+            /*Log.d("Gosmore", "zoom = " + mRenderer.p.zoom);
+            if (mRenderer.p.zoom < 100000000 && activity.pakType < 2) {
+            	activity.showDialog(Math.abs(mRenderer.p.lat) < 1 &&
+            		Math.abs(mRenderer.p.lon) < 1 ? 3 : 4);
+            }*/
+        }
+        // pid = action >> MotionEvent.ACTION_POINTER_ID_SHIFT;
+        mPreviousX = x;
+        mPreviousY = y;  
+    	}
+    	else {
+    		try {
+    			int pcnt = (Integer) getPointerCount.invoke (e);
+    			float x = (Float) getPointerCount.invoke (e, 0);
+    			//getAction  & MotionEvent.ACTION_MASK
+    		} catch (InvocationTargetException ite) {}
+    		  catch (IllegalAccessException ie) {}
+    	}
+        requestRender();
+        return true;
+    }
+    private float[] lastAccels=new float[3];
+    
+    public SensorEventListener accListener=new SensorEventListener() {
+    	public void onSensorChanged(SensorEvent e) {
+    		System.arraycopy(e.values, 0, lastAccels, 0, 3);
+    	}
+    	public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+	};
+
+    public final SensorEventListener magListener = new SensorEventListener() {
+        public void onSensorChanged(SensorEvent e) {
+        	double g = Math.sqrt(lastAccels[0]*lastAccels[0]+lastAccels[1]*lastAccels[1]+
+			  lastAccels[2]*lastAccels[2]);
+        	if (g > 5) {// If we are not in (momentary) free fall
+        		float east[] = { e.values[1]*lastAccels[2]-e.values[2]*lastAccels[1],
+        				         e.values[2]*lastAccels[0]-e.values[0]*lastAccels[2],
+        				         e.values[0]*lastAccels[1]-e.values[1]*lastAccels[0]};
+        		mRenderer.threeD = lastAccels[2]*2 < g; 
+        		int d = (int)(180/Math.PI*(lastAccels[2]*2 < g
+         				? Math.atan2(east[2],(east[0]*lastAccels[1]-east[1]*lastAccels[0])/g)
+          				: -Math.atan2((east[1]*lastAccels[2]-east[2]*lastAccels[1])/g, east[0])))
+          				 - mRenderer.declination;
+        		mRenderer.dirSum += mRenderer.dirSum < 90 * mRenderer.dirCnt ?
+        				  (d + 540) % 360 - 180 : mRenderer.dirSum > 270 * mRenderer.dirCnt
+        				  ? (d + 540) % 360 + 180 : (d + 720) % 360; 
+        		mRenderer.dirCnt++;
+        		if (Math.abs(mRenderer.dirSum / mRenderer.dirCnt - mRenderer.p.dir) >
+        		    30 / mRenderer.dirCnt + 10) {
+        			//Log.d("Gosmore", "Azimuth = " + mRenderer.p.dir);
+        			mRenderer.p.dir = mRenderer.dirSum / mRenderer.dirCnt;
+        			mRenderer.dirSum = 0;
+        			mRenderer.dirCnt = 0;
+        			requestRender();
+        		}
+        	} 
+        	/*float gg = lastAccels[0]*lastAccels[0]+lastAccels[1]*lastAccels[1]+
+				lastAccels[2]*lastAccels[2];
+        	if (gg > 5*5) { // If we are not in (momentary) free fall
+        		float p = (e.values[0]*lastAccels[0]+e.values[1]*lastAccels[1]+
+        				e.values[2]*lastAccels[2])/gg;
+        		mRenderer.p.dir = (int) ((lastAccels[2]*lastAccels[2]*3 > gg ? Math.atan2(e.values[0]-p*lastAccels[0], e.values[1] - p*lastAccels[1]) :
+		            lastAccels[1]*lastAccels[1]*3 > gg ? Math.PI - Math.atan2(e.values[0]-p*lastAccels[0], e.values[2] - p*lastAccels[2]) :
+		    	        Math.atan2(e.values[2]-p*lastAccels[2], e.values[1] - p*lastAccels[1]))
+		    	        *(180/Math.PI)) - mRenderer.declination; 
+        		mRenderer.threeD = lastAccels[1]*lastAccels[1]*3 > gg; 
+        		requestRender();
+        	}*/
+        }      
+        public void onAccuracyChanged(Sensor s, int accuracy) {}
+    };
+  
+    public MapRenderer mRenderer;
+}
+
+class MapRenderer implements GLSurfaceView.Renderer {
+	private int width, height;
+	public int mPixelX = 0, mPixelY = 0; // These are only modified by the UI thread
+	public int oldPixelX = 0, oldPixelY = 0;
+    public int bitmapWidth, bitmapHeight;
+    public int dirSum = 0, dirCnt = 0, latLonCnt = 0;
+    public long zTime = 0;
+    public float zExp, speed, bearing;
+    public double latSum = 0, lonSum = 0;
+    public Bitmap mBitmap, mIcons; 
+    public Paint mClearPaint;
+    public Place p; // = Gosmore.s.searchResult
+    public MapView mapView;
+    public int mTextureID, icons;
+    public boolean route = false, startR = false, doNavigate = false;
+    public ProgressDialog rProgress; 
+	public TextToSpeech mTts;
+	public boolean tts = false, follow = false;
+    //public Context mContext;
+    /*public class Btn { int x, y, w, h, draw; }
+    public Btn btn[] = {
+    		
+    }*/
+
+/*    public float mTexelWidth;  // Convert texel to U
+    public float mTexelHeight; // Convert texel to V
+    public int mU;
+    public int mV;
+    public int mLineHeight;
+*/    //public ArrayList<Label> mLabels = new ArrayList<Label>();
+
+    public Canvas mCanvas;
+    public Paint mTextPaint;
+    public boolean fast = false, threeD = false;
+    public int declination = 0;
+    public void drawTeks(String s, int x, int y, float sin, float cos) {
+    	if (!fast) {
+          Matrix m = mCanvas.getMatrix ();
+          m.setSinCos (-sin, cos, x, y);  
+          mCanvas.setMatrix (m);
+          mCanvas.drawText(s, x, y, mTextPaint);
+    	}
+    }      
+    public long last = 0, fps = 0, frame = 0;
+    public native void render (double lon, double lat, int dir, int zoom,
+    		boolean threeD,	boolean follow, int width, int height);
+    public native String navigate (double lon, double lat, float speed,
+    		float bearing);
+    public native void startRoute (double lon, double lat);
+    public native void endRoute (double lon, double lat, boolean fastest,
+    		int vehicle);
+    public native int doRoute ();
+    public MapRenderer(Context context) {
+    	//mContext = context;
+    }  
+    public SharedPreferences prefs; 
+    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+    	mTextPaint = new Paint();       
+        mTextPaint.setAntiAlias(false);
+        mTextPaint.setTextSize(16);
+        mTextPaint.setColor(Color.BLACK);//0xFF000000);
+        mTextPaint.setTextAlign(Paint.Align.CENTER);
+
+        //mTextPaint.setPadding(3, 3, 3, 3);
+        gl.glDisable(GL10.GL_DITHER);
+        gl.glClearColor(1f,1f,1f, 1f);
+  	  	prefs = PreferenceManager.getDefaultSharedPreferences(mapView.getContext());
+    }
+
+    public void onSurfaceChanged(GL10 gl, int w, int h) {
+    	width = w;
+    	height = h;
+        gl.glViewport(0, 0, w, h);
+        //lm = new LabelMaker (false, 64,64);
+        bitmapWidth = w - 1;
+        bitmapWidth |= bitmapWidth >> 1;
+        bitmapWidth |= bitmapWidth >> 2;
+        bitmapWidth |= bitmapWidth >> 4;
+        bitmapWidth |= bitmapWidth >> 8;
+        bitmapWidth++;
+        bitmapHeight = h - 1;
+        bitmapHeight |= bitmapHeight >> 1;
+        bitmapHeight |= bitmapHeight >> 2;
+        bitmapHeight |= bitmapHeight >> 4;
+        bitmapHeight |= bitmapHeight >> 8;
+        bitmapHeight++;
+/*        mTexelWidth = (float) (1.0 / bitmapWidth);
+        mTexelHeight = (float) (1.0 / bitmapHeight);*/
+        mClearPaint = new Paint();
+        mClearPaint.setARGB(0, 0, 0, 0);
+        mClearPaint.setStyle(Style.FILL);
+
+        //initialize(gl);
+        int[] textures = new int[2];
+        gl.glGenTextures(2, textures, 0);
+        mTextureID = textures[1];
+        icons = textures[0];
+        gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
+
+        // Use Nearest for performance.
+        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
+                GL10.GL_NEAREST);
+        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
+                GL10.GL_NEAREST);
+
+        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
+                GL10.GL_CLAMP_TO_EDGE);
+        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
+                GL10.GL_CLAMP_TO_EDGE);
+
+        gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
+                GL10.GL_REPLACE); // GL_MODULATE also works here.
+
+        gl.glBindTexture(GL10.GL_TEXTURE_2D, icons);
+        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
+                GL10.GL_NEAREST);
+        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
+                GL10.GL_NEAREST);
+
+        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
+                GL10.GL_CLAMP_TO_EDGE);
+        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
+                GL10.GL_CLAMP_TO_EDGE);
+
+        gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
+                GL10.GL_REPLACE); // GL_MODULATE also works here.
+        //int iw = mIcons.getWidth();
+        //int ih = mIcons.getHeight();
+        /*int[] pixels = new int[iw*ih];
+        mIcons.getPixels(pixels, 0, iw, 0, 0, iw, ih);
+        mBitmap = Bitmap.createBitmap(pixels, 0, iw, iw, ih,
+                                       Bitmap.Config.ARGB_8888);*/
+        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mIcons, 0);  
+        
+        mBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, //Bitmap.Config.ARGB_4444); 
+            	Bitmap.Config.ALPHA_8);
+        mCanvas = new Canvas(mBitmap);
+    } 
+           
+    public void onDrawFrame(GL10 gl) {
+    	if (startR)	{
+    		startRoute (p.lon, p.lat);
+    		startR = false;
+    	}
+    	if (route) {
+    	  //Log.d ("Gosmore", "start route");
+    	  endRoute (p.lon, p.lat, prefs.getBoolean ("fastest", true),
+    			Integer.parseInt(prefs.getString ("vehicle", "12")));
+    	  int p; 
+    	  while ((p = doRoute()) < 999 && p >= 0 && route) rProgress.setProgress (p);
+    	  route = false;
+    	  //Log.d ("Gosmore", "p = " + p);
+    	  rProgress.dismiss();
+    	}
+    	if (doNavigate) {
+    		doNavigate = false;
+        	String msg = navigate (p.lon, p.lat, speed, bearing);
+        	if (msg != "" && tts) mTts.speak(msg, TextToSpeech.QUEUE_FLUSH, null);
+    	}
+
+    	gl.glViewport(0,0,width,height);
+    	gl.glMatrixMode(GL10.GL_PROJECTION);
+      	gl.glLoadIdentity();
+
+    	gl.glOrthof(0.0f,width,height,0.0f,-1.0f,1.0f);
+
+    	gl.glMatrixMode(GL10.GL_MODELVIEW);	// Really necessary ?
+    	gl.glLoadIdentity();				// Really necessary ?
+    	gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
+    	gl.glDisable(GL10.GL_DEPTH_TEST);
+
+        if (!fast) mBitmap.eraseColor(0); // I don't think this can be done with drawRect,
+        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+        gl.glDisable(GL10.GL_TEXTURE_2D);
+
+        gl.glBindTexture(GL10.GL_TEXTURE_2D, icons); 
+        gl.glShadeModel(GL10.GL_FLAT);
+//        gl.glEnable(GL10.GL_BLEND);  
+        //gl.glEnable(GL10.GL_LINE_SMOOTH); // If this is enabled on the LG OO,
+        // all lines will have width 1.
+        
+        //gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
+        // Not sure what this does.
+        
+        //mouseEv (mPixelX, mPixelY, 0, 1, false);
+        if (zTime != 0) {
+        	long now = SystemClock.uptimeMillis();
+        	p.zoom = (int)(p.zoom * Math.exp (zExp * (now - zTime)));
+        	zTime = now;
+        	mapView.requestRender();
+        }
+        if (p.zoom < 999) p.zoom = 999;
+        else if (p.zoom > 500000000) p.zoom = 500000000;
+        double z = 360.0 / 4294967296.0 * (threeD ? 10000 : p.zoom) / width;
+        if (!threeD && prefs.getBoolean ("north2d", false)) p.dir = 0;
+        int diffY = threeD ? 0 : mPixelY-oldPixelY;
+        p.lat += z * (diffY * Math.cos(Math.PI/180*p.dir) +
+        		      (oldPixelX-mPixelX)*Math.sin(Math.PI/180*p.dir));
+        p.lon += z * ((oldPixelX-mPixelX)*Math.cos(Math.PI/180*p.dir) -
+		  diffY*Math.sin(Math.PI/180*p.dir))
+		  / Math.cos(Math.PI/180*p.lat);
+        if (threeD) p.dir += mPixelY - oldPixelY;
+        oldPixelX = mPixelX; 
+        oldPixelY = mPixelY; 
+    	render(p.lon, p.lat, p.dir, threeD ? 50000 : p.zoom, threeD, follow, width, height);
+    
+    	/*long now = System.currentTimeMillis();
+        drawTeks (fps + "", 10, 250, 0, 1);
+    	if (now - last > 1000) {
+    	  fps = frame;
+    	  frame = 0; 
+    	  last = now;
+    	}  
+    	else frame++;*/
+               
+    	if (!fast) {
+        gl.glEnable(GL10.GL_BLEND);   
+        gl.glEnable(GL10.GL_TEXTURE_2D);
+        //gl.glShadeModel(GL10.GL_FLAT);
+        gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
+        
+/*        gl.glMatrixMode(GL10.GL_PROJECTION);
+        gl.glPushMatrix();
+        gl.glLoadIdentity();
+        gl.glOrthof(0.0f, width, 0.0f, height, 0.0f, 1.0f); 
+        gl.glMatrixMode(GL10.GL_MODELVIEW);
+        gl.glPushMatrix();
+        gl.glLoadIdentity();
+        // Magic offsets to promote consistent rasterization.
+        gl.glTranslatef(0.375f, 0.375f, 0.0f);
+//        beginDrawing(gl, width, height);
+        gl.glPushMatrix();*/
+        /*float snappedX = 10;
+        float snappedY = 10;
+        gl.glTranslatef(snappedX, snappedY, 0.0f);*/
+        //Label label = mLabels.get(id);
+        //Log.d("Gosmore", "w" + mBitmap.getWidth() + " h" + mBitmap.getHeight() + " x"+mBitmap.getRowBytes());
+        //Log.d("Gosmore", "w" + mIcons.getWidth() + " h" + mIcons.getHeight() + " x"+mIcons.getRowBytes());
+        gl.glBindTexture(GL10.GL_TEXTURE_2D, icons);  
+
+/*        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mIcons, 0);  
+        //mBitmap2.recycle();
+
+        int[] crop2 = { 0, height - 1, width - 1, -height + 1 };
+        ((GL11)gl).glTexParameteriv(GL10.GL_TEXTURE_2D,
+                GL11Ext.GL_TEXTURE_CROP_RECT_OES, crop2, 0); //label.mCrop, 0);
+        gl.glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
+        ((GL11Ext)gl).glDrawTexiOES((int) 1, (int) 1, 0,
+                (int) width - 1, (int) height - 1);    
+*/
+        gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
+        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0);
+          
+        int[] crop = { 0, height - 1, width - 1, -height + 1 };
+        ((GL11)gl).glTexParameteriv(GL10.GL_TEXTURE_2D,
+                GL11Ext.GL_TEXTURE_CROP_RECT_OES, crop, 0); //label.mCrop, 0);
+        gl.glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
+        ((GL11Ext)gl).glDrawTexiOES((int) 1, (int) 1, 0,
+                (int) width - 1, (int) height - 1);    
+        ((GL11Ext)gl).glDrawTexiOES((int) -1, (int) -1, 0, 
+                (int) width - 1, (int) height - 1);    
+        gl.glColor4x(0,0,0,0x10000);//0x10000, 0x10000, 0x10000, 0x10000); 
+        ((GL11Ext)gl).glDrawTexiOES((int) 0, (int) 0, 0,
+                (int) width - 1, (int) height - 1);    
+        /*gl.glPopMatrix();  
+ 
+        gl.glDisable(GL10.GL_BLEND);
+        gl.glMatrixMode(GL10.GL_PROJECTION);
+        gl.glPopMatrix();
+        gl.glMatrixMode(GL10.GL_MODELVIEW);
+        gl.glPopMatrix();*/  
+    	}
+    	/*
+        draw(gl, 10, 10, id);*/
+//        endDrawing(gl);
+    }
+}
diff --git a/src/org/osmu/gosmore/Place.java b/src/org/osmu/gosmore/Place.java
new file mode 100755
index 0000000..cfccd3f
--- /dev/null
+++ b/src/org/osmu/gosmore/Place.java
@@ -0,0 +1,10 @@
+package org.osmu.gosmore;
+
+import java.io.Serializable;
+
+public class Place implements Serializable {
+	static final long serialVersionUID = 6618718668L;
+      double lat, lon;
+      int zoom, dir; // Currently dir is always 0
+      String name;
+}
diff --git a/src/org/osmu/gosmore/Preferences.java b/src/org/osmu/gosmore/Preferences.java
new file mode 100755
index 0000000..963215c
--- /dev/null
+++ b/src/org/osmu/gosmore/Preferences.java
@@ -0,0 +1,54 @@
+package org.osmu.gosmore;
+
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+
+public class Preferences extends PreferenceActivity {
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        setPreferenceScreen(createPreferenceHierarchy());
+    }
+
+    private PreferenceScreen createPreferenceHierarchy() {
+        PreferenceScreen root = getPreferenceManager().createPreferenceScreen(this);
+/*        PreferenceCategory inlinePrefCat = new PreferenceCategory(this);
+        inlinePrefCat.setTitle(R.string.inline_preferences);
+        root.addPreference(inlinePrefCat);*/
+        
+        CheckBoxPreference fastest = new CheckBoxPreference(this);
+        fastest.setDefaultValue(true);
+        fastest.setKey("fastest");
+        fastest.setTitle(R.string.fastest);
+        fastest.setSummary(R.string.summary_fastest);
+        root.addPreference(fastest);
+
+        CheckBoxPreference north2d = new CheckBoxPreference(this);
+        north2d.setKey("north2d");
+        north2d.setTitle(R.string.north2d);
+        north2d.setSummary(R.string.summary_north2d);
+        root.addPreference(north2d);
+ 
+        ListPreference vehicle = new ListPreference(this);
+        vehicle.setEntries(R.array.vehicle_entries);
+        vehicle.setEntryValues(R.array.vehicle_values);
+        vehicle.setDialogTitle(R.string.vehicle);
+        vehicle.setKey("vehicle");
+        vehicle.setTitle(R.string.vehicle);
+        vehicle.setSummary(R.string.summary_vehicle);
+        /*dialogBasedPrefCat*/ root.addPreference(vehicle);
+
+        ListPreference ttsLocale = new ListPreference(this);
+        ttsLocale.setEntries(R.array.tts_entries);
+        ttsLocale.setEntryValues(R.array.tts_values);
+        ttsLocale.setDialogTitle(R.string.tts);
+        ttsLocale.setKey("tts");
+        ttsLocale.setTitle(R.string.tts);
+        ttsLocale.setSummary(R.string.summary_tts);
+        /*dialogBasedPrefCat*/ root.addPreference(ttsLocale);
+        return root;
+    }
+}
\ No newline at end of file
diff --git a/src/org/osmu/gosmore/Recent.java b/src/org/osmu/gosmore/Recent.java
new file mode 100755
index 0000000..05b3ee0
--- /dev/null
+++ b/src/org/osmu/gosmore/Recent.java
@@ -0,0 +1,31 @@
+package org.osmu.gosmore;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public class Recent extends ListActivity {
+   	protected void onListItemClick(ListView l, View v, int position, long id)
+   	{
+   		Gosmore g = (Gosmore)getApplicationContext();
+   		g.s.searchResult.lat = g.s.recent.get(g.s.recent.size()-1-position).lat;
+   		g.s.searchResult.lon = g.s.recent.get(g.s.recent.size()-1-position).lon;
+   		g.s.searchResult.dir = g.s.recent.get(g.s.recent.size()-1-position).dir;
+   		g.s.searchResult.zoom = g.s.recent.get(g.s.recent.size()-1-position).zoom;
+   		finish(); // Easier way to do a deep copy ?
+   	}
+    @Override  
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        //setContentView(R.layout.search);
+        Gosmore g = ((Gosmore)getApplicationContext());
+        String names[] = new String[g.s.recent.size()];
+        for (int i = 0; i < g.s.recent.size(); i++) {
+        	names[g.s.recent.size()-1-i] = g.s.recent.get(i).name;
+        }
+        setListAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, names));
+    }
+}
diff --git a/src/org/osmu/gosmore/Search.java b/src/org/osmu/gosmore/Search.java
new file mode 100755
index 0000000..658fbb7
--- /dev/null
+++ b/src/org/osmu/gosmore/Search.java
@@ -0,0 +1,131 @@
+package org.osmu.gosmore;
+
+import java.util.ArrayList;
+
+import android.app.ListActivity;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+public class Search extends ListActivity implements TextWatcher {
+    public Search ()
+    {
+    	super();
+    	adap = new EfficientAdapter ();
+    }
+    private EfficientAdapter adap;
+    private EditText et;
+    
+    //---- It's also a TextWatcher for the EditText
+  	public void afterTextChanged (Editable s){
+          adap.results.clear();
+          this.search (et.getText().toString());
+          setListAdapter(adap);
+   	}
+   	public void beforeTextChanged (CharSequence s, int start, int count, int after){}
+   	public void onTextChanged (CharSequence s, int start, int before, int count){}
+   	//---- End TextWatcher
+
+   	protected void onListItemClick(ListView l, View v, int position, long id)
+   	{
+		Gosmore g = (Gosmore)getApplicationContext(); 
+		g.s.searchResult.lat = adap.results.get(position).lat;
+   		g.s.searchResult.lon = adap.results.get(position).lon;
+   		g.s.searchResult.zoom = adap.results.get(position).zoom;
+   		g.s.searchResult.dir = 0;
+   		g.s.searchResult.name = adap.results.get(position).s;
+   		Place p = new Place();
+   		p.lat = g.s.searchResult.lat;
+   		p.lon = g.s.searchResult.lon;
+   		p.zoom = g.s.searchResult.zoom;
+   		p.dir = g.s.searchResult.dir;
+   		p.name = g.s.searchResult.name;
+   		g.s.recent.add(p);
+   		if (g.s.recent.size() > 40) g.s.recent.remove(0);
+   		g.s.search = et.getText().toString();
+   		finish();
+   	}  
+    @Override  
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.search);
+   	    adap.icons = ((Gosmore)getApplicationContext()).icons;
+        adap.mInflater = getLayoutInflater();
+
+        et = (EditText) findViewById (R.id.search_query);
+        //et.setInputType(InputType.TYPE_CLASS_TEXT|0x00080000);
+        et.addTextChangedListener(this);
+        et.setText(((Gosmore)getApplicationContext()).s.search);
+        afterTextChanged (null);
+        et.requestFocus();//|0x00080000
+    }  
+    //public int zoom;
+    //public native void setLocation (double lon, double lat);
+    public native void search (String s);
+    public void searchResult(int x, int y, int w, int h,
+    		double dist, int u, int v, String s,
+    		double lon, double lat, int _zoom) {
+        adap.results.add(new ResultData());
+        adap.results.get(adap.results.size()-1).x = x;
+        adap.results.get(adap.results.size()-1).y = y;
+        adap.results.get(adap.results.size()-1).w = w;
+        adap.results.get(adap.results.size()-1).h = h;
+        adap.results.get(adap.results.size()-1).dist = dist;
+        adap.results.get(adap.results.size()-1).s = s;
+        adap.results.get(adap.results.size()-1).v = v;
+        adap.results.get(adap.results.size()-1).u = u;
+        adap.results.get(adap.results.size()-1).lon = lon;
+        adap.results.get(adap.results.size()-1).lat = lat;
+        adap.results.get(adap.results.size()-1).zoom = _zoom;
+    } 
+}
+
+class ResultData {
+	public ResultData () {}
+	public double dist, lon, lat;
+	public String s;
+	public int u, v, x, y, w, h, zoom;
+}
+ 
+class EfficientAdapter extends BaseAdapter {
+    public LayoutInflater mInflater;
+    public ArrayList<ResultData> results;
+    public Bitmap icons;
+    public EfficientAdapter() {
+        // Cache the LayoutInflate to avoid asking for a new one each time.
+        results = new ArrayList<ResultData>();
+    }
+    public int getCount() {
+        return results.size();
+    }
+    public Object getItem(int position) {
+        return position;
+    }
+    public long getItemId(int position) {
+        return position;
+    }
+    public View getView(int position, View convertView, ViewGroup parent) {
+    	//if (convertView == null) {
+    	convertView = mInflater.inflate(R.layout.search_result, null);
+    	TextView t = (TextView) convertView.findViewById(R.id.result_text);
+    	t.setText(results.get(position).s);
+    	TextView d = (TextView) convertView.findViewById(R.id.distance);
+    	double dist = results.get(position).dist;
+    	d.setText(dist >= 998 ? "Far " : dist > 1 ? (int) dist + " km " :
+    				(int)(dist*1000) + " m ");   
+    	ImageView i = (ImageView) convertView.findViewById(R.id.result_icon);
+    	if (results.get(position).w > 0) i.setImageBitmap(Bitmap.createBitmap(icons,results.get(position).x, 
+    				results.get(position).y, results.get(position).w, results.get(position).h));
+    	return convertView;
+    }
+}
\ No newline at end of file
diff --git a/src/org/osmu/gosmore/Update.java b/src/org/osmu/gosmore/Update.java
new file mode 100755
index 0000000..cc9a1f1
--- /dev/null
+++ b/src/org/osmu/gosmore/Update.java
@@ -0,0 +1,243 @@
+package org.osmu.gosmore;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.StatFs;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+public class Update extends Activity implements LocationListener {
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        requestWindowFeature(Window.FEATURE_PROGRESS);
+        setContentView(R.layout.update);
+        setProgressBarVisibility(true);
+          
+        String code = currentBbox ();
+
+        //if (!code.equals("default")) ((TextView) findViewById(R.id.update_description)).setText (code);
+        if (((Gosmore) getApplication()).updateProgress >= 0) {
+    		((TextView) findViewById(R.id.update_msg)).setText( 
+    				((Gosmore) getApplication()).updateMsg);
+        }
+        else if (code.equals("")) {
+        	((Gosmore)getApplication()).updateMsg = "Cannot update a custom map";
+        }
+        else {
+            //else ((TextView) findViewById(R.id.update_description)).setText (R.string.default_update);
+        	final UpdateTask dft;
+            dft = new UpdateTask ();
+            dft.gosmore = (Gosmore) getApplication();
+            dft.gosmore.updateProgress = 0;
+            dft.gosmore.cancelUpdate = false;
+            setProgress(0); // Redundant ?
+            if (dft.gosmore.s.searchResult.lon == 0 && dft.gosmore.s.searchResult.lat == 0) {
+            	// New install. Center the view in anticipation of the initial download.
+                ((LocationManager) getSystemService(LOCATION_SERVICE)).requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 10f, this);
+            }
+          
+            dft.notification = new Notification(R.drawable.icon, "Downloading Map", System.currentTimeMillis());
+            dft.notification.flags = dft.notification.flags | Notification.FLAG_ONGOING_EVENT;
+            dft.notification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.download_progress);
+            dft.notification.contentIntent = /*pendingIntent;*/ PendingIntent.getActivity(this, 0, new Intent(this, Update.class), 0);
+            //notification.contentView.setImageViewResource(R.id.status_icon, R.drawable.ic_menu_save);
+            dft.notification.contentView.setTextViewText(R.id.status_text, "Downloading map");
+            //notification.contentView.setProgressBar(R.id.status_progress, 100, progress, false);
+          
+            //notification.setLatestEventInfo(getApplicationContext(), "Downloading", "Map", contentIntent);
+            dft.nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+            dft.nm.notify (1, dft.notification);
+            dft.execute(code);
+        }
+        ((Button)findViewById(R.id.cancel_update)).setOnClickListener(new Button.OnClickListener() {
+        	public void onClick (View v) {
+        		((Gosmore)getApplication()).cancelUpdate = true;
+        	}
+        });
+    }
+    // ---- Location Listener methods ----
+    public void onLocationChanged(Location location) {
+    	((LocationManager) getSystemService(LOCATION_SERVICE)).removeUpdates(this);
+    	((Gosmore) getApplication()).s.searchResult.lon = location.getLongitude();
+    	((Gosmore) getApplication()).s.searchResult.lat = location.getLatitude();
+    	((Gosmore) getApplication()).s.searchResult.zoom = 4000000;
+    }
+    public void onProviderDisabled(String provider) {}
+    public void onProviderEnabled(String provider) {}
+    public void onStatusChanged(String provider, int status, Bundle extras) {}
+    // ---- Location Listener methods ----
+
+    protected void onResume()
+    {
+    	super.onResume();
+    	ProgressBar pb = (ProgressBar) findViewById(R.id.update_progress);
+    	pb.setProgress(((Gosmore)getApplication()).updateProgress);
+    	((Gosmore)getApplication()).updateBar = pb;
+    	((Gosmore)getApplication()).updateMsgView = ((TextView) findViewById(R.id.update_msg));
+    	((Gosmore)getApplication()).updateMsgView.setText(((Gosmore)getApplication()).updateMsg);
+    	((Gosmore)getApplication()).updateCancel = ((Button) findViewById(R.id.cancel_update));
+    	if (((Gosmore)getApplication()).cancelUpdate) ((Gosmore)getApplication()).updateCancel.setEnabled(false);
+    }
+    protected void onDestroy ()
+    {
+    	((Gosmore)getApplication()).updateBar = null;
+    	((Gosmore)getApplication()).updateMsgView = null;
+    	((Gosmore)getApplication()).updateCancel = null;
+    	super.onDestroy ();
+    }
+    private native String currentBbox ();
+}
+
+class UpdateTask extends AsyncTask<String, Integer, String> {
+	public Gosmore gosmore;
+	Notification notification;
+	NotificationManager nm;
+    protected String doInBackground(String... code) {
+    	PipedInputStream in = new PipedInputStream();
+        File sd = Environment.getExternalStorageDirectory();
+        final long modifiedTm = (new File (sd, "/gosmore/" + code[0] + ".pak")).lastModified();
+        try {
+        	final String myurl = "http://dev.openstreetmap.de/gosmore/" + code[0] + ".zip";
+      	  	final PipedOutputStream out = new PipedOutputStream(in);
+        	new Thread(
+        	    new Runnable(){
+        	        public void run(){
+        	            for (int downloaded = 0, l = 1, count; l > 0 && !gosmore.cancelUpdate;) {
+        	        		try {
+        	        			URL u = new URL(myurl);
+        	        			URLConnection cx = u.openConnection();
+        	                	cx.setRequestProperty("Range", "bytes=" + downloaded + "-");
+        	                	cx.setReadTimeout(60000); 
+        	                	cx.setConnectTimeout(60000);
+        	                	//cx.connect(); // getContentLen will do it for us.
+      	                		if ((l = cx.getContentLength()) > 0) {
+      	                			Log.d("Gosmore", "Start "+cx.getLastModified()+" len "+modifiedTm);
+            	                	if (cx.getLastModified() < modifiedTm) {
+            	                		l = 0;
+            	                		break;
+            	                	}
+      	                			//Log.d("Gosmore", "Start "+downloaded+" len "+l + " "+ cx.getHeaderField("Accept-Ranges")+ " " + cx.getResponseCode());
+      	                			InputStream is = cx.getInputStream();
+      	                			byte[] buf = new byte[1500]; 
+      	                			for (; (count=is.read(buf, 0, 1500)) != -1; l-=count) {
+      	                				if(count > 0) out.write(buf,0,count);
+      	                				downloaded += count;
+      	                			}
+       	                		}
+      	                		else l = 1;
+        	                } catch (MalformedURLException mue) {
+        	                	gosmore.updateMsg = "Bad URL. Retrying.";
+        	                } catch (IOException ioe) {
+        	                	gosmore.updateMsg = "Network Error. Retrying.";
+        	                } catch (SecurityException se) {
+        	                	gosmore.updateMsg = "Security error. Retrying.";
+        	                }
+        	                try {
+        	                	if (l > 0) Thread.sleep (1);
+        	                } catch(InterruptedException e) {}
+        	        	}
+                		Log.d("Gosmore", "Leaving download thread "+gosmore.cancelUpdate);
+                		try { out.close(); } catch (IOException ioe) {}
+        	        }
+        	    }
+        	).start();
+        } catch(IOException a) {Log.d ("Gosmore", "1st");}
+        Log.d ("Gosmore", "a");
+        try {
+            byte[] buffer = new byte[1024];
+            ZipInputStream dis = new ZipInputStream (in);
+            ZipEntry entry;
+
+            int length, done = 0;
+            Log.d ("Gosmore", "b");
+            if ((entry = dis.getNextEntry()) != null) {
+                Log.d ("Gosmore", "c");
+              StatFs stat = new StatFs (sd.getPath());
+              if (stat.getAvailableBlocks() * (long) stat.getBlockSize() <
+            		  entry.getSize()) {
+            	  gosmore.updateMsg = "Error: At least " + 
+            	    (entry.getSize() / 1024/1024) + "MB storage space is needed";
+            	  publishProgress(-1);
+              }
+              else {
+                  gosmore.updateMsg = "" + (int)(entry.getSize()/(2048*1024))+ " MB";
+                  publishProgress(-1);
+            	  File f = new File(sd, "/gosmore/tmp.pak");
+            	  FileOutputStream fos = new FileOutputStream(f);
+            	  while (!gosmore.cancelUpdate && (length = dis.read(buffer)) != -1) {
+            		  fos.write(buffer, 0, length);
+            		  if ((done >> 20) < ((done + length) >> 20)) {
+            			  publishProgress(done / (int)(entry.getSize() / 100));
+            			  notification.contentView.setProgressBar(R.id.status_progress, 100, done / (int)(entry.getSize() / 100), false);
+            			  nm.notify(1, notification);
+            		  }
+            		  done += length;
+            	  }
+            	  fos.close();
+            	  //Log.d("Gosmore", "k" + done + " " + entry.getSize());
+            	  if (done == entry.getSize()) {
+            		  File to = new File (sd, "/gosmore/" + code[0] + ".pak");
+            		  f.renameTo(to);
+            		  gosmore.updateMsg = "Download successful.";
+              	  }
+              	  else gosmore.updateMsg = "Download incomplete. Aborting";
+                  Log.d ("Gosmore", "a");
+              } // There was enough space with we started.
+            } // The zip looks valid
+            else gosmore.updateMsg = gosmore.cancelUpdate ? "Update cancelled" :
+            	"No new map available."; // Empty file.
+        } catch (IOException ioe) {
+        	gosmore.updateMsg = "File Error";
+        } catch (SecurityException se) {
+        	gosmore.updateMsg = "Security error";
+        }
+        //publishProgress(100);
+        nm.cancel (1);
+        gosmore.updateProgress = -1; // Ready for a new update
+        return null;
+    }
+
+    protected void onProgressUpdate(Integer... progress) {
+    	if (progress[0] >= 0) {
+    		if (gosmore.updateBar != null) gosmore.updateBar.setProgress(progress[0]);
+    		gosmore.updateProgress = progress[0];
+    	}
+    	else if (gosmore.updateMsgView != null) {
+    		gosmore.updateMsgView.setText(gosmore.updateMsg);
+    	}
+    }
+
+    protected void onPostExecute(String result) {
+  		Log.d ("Gosmore", gosmore.updateMsg + (gosmore.updateMsgView != null ? " view" : " noview"));
+    	if (gosmore.updateMsgView != null) gosmore.updateMsgView.setText(gosmore.updateMsg);
+    	if (gosmore.updateCancel != null) gosmore.updateCancel.setEnabled(false);
+    	gosmore.cancelUpdate = true;
+    }
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/gosmore.git



More information about the Pkg-grass-devel mailing list