diff --git a/src/org/oscim/app/LocationHandler.java b/src/org/oscim/app/LocationHandler.java
index 82284bd0..1c73e8ce 100644
--- a/src/org/oscim/app/LocationHandler.java
+++ b/src/org/oscim/app/LocationHandler.java
@@ -15,7 +15,7 @@
 package org.oscim.app;
 
 import org.oscim.core.GeoPoint;
-import org.oscim.core.MapPosition;
+import org.oscim.view.MapPosition;
 
 import android.content.Context;
 import android.location.Criteria;
diff --git a/src/org/oscim/app/TileMap.java b/src/org/oscim/app/TileMap.java
index ebc8a468..48dba1f6 100755
--- a/src/org/oscim/app/TileMap.java
+++ b/src/org/oscim/app/TileMap.java
@@ -9,12 +9,12 @@ import org.oscim.app.filefilter.ValidRenderTheme;
 import org.oscim.app.filepicker.FilePicker;
 import org.oscim.app.preferences.EditPreferences;
 import org.oscim.core.GeoPoint;
-import org.oscim.core.MapPosition;
 import org.oscim.database.MapDatabases;
 import org.oscim.theme.InternalRenderTheme;
 import org.oscim.utils.AndroidUtils;
 import org.oscim.view.DebugSettings;
 import org.oscim.view.MapActivity;
+import org.oscim.view.MapPosition;
 import org.oscim.view.MapView;
 
 import android.annotation.TargetApi;
diff --git a/src/org/oscim/core/MercatorProjection.java b/src/org/oscim/core/MercatorProjection.java
index b9e2df14..8220144b 100644
--- a/src/org/oscim/core/MercatorProjection.java
+++ b/src/org/oscim/core/MercatorProjection.java
@@ -14,6 +14,8 @@
  */
 package org.oscim.core;
 
+import org.oscim.view.MapPosition;
+
 /**
  * An implementation of the spherical Mercator projection.
  */
diff --git a/src/org/oscim/core/Tag.java b/src/org/oscim/core/Tag.java
index 2c8c64a9..fca297bc 100644
--- a/src/org/oscim/core/Tag.java
+++ b/src/org/oscim/core/Tag.java
@@ -17,6 +17,9 @@ package org.oscim.core;
 /**
  * A tag represents an immutable key-value pair.
  */
+
+// TODO: use own stringshare method instead of internalized strings
+
 public class Tag {
 	private static final char KEY_VALUE_SEPARATOR = '=';
 	/**
diff --git a/src/org/oscim/database/oscimap/MapDatabase.java b/src/org/oscim/database/oscimap/MapDatabase.java
index 5d1e2dd8..78257ac4 100644
--- a/src/org/oscim/database/oscimap/MapDatabase.java
+++ b/src/org/oscim/database/oscimap/MapDatabase.java
@@ -65,8 +65,8 @@ public class MapDatabase implements IMapDatabase {
 	private static final String CACHE_FILE = "%d-%d-%d.tile";
 
 	private static final String SERVER_ADDR = "city.informatik.uni-bremen.de";
-	// private static final String URL = "/osci/map-live/";
-	private static final String URL = "/osci/oscim/";
+	private static final String URL = "/osci/map-live/";
+	// private static final String URL = "/osci/oscim/";
 
 	private final static float REF_TILE_SIZE = 4096.0f;
 
diff --git a/src/org/oscim/utils/GLSurfaceView.java b/src/org/oscim/utils/GLSurfaceView.java
index c775af69..5601345e 100644
--- a/src/org/oscim/utils/GLSurfaceView.java
+++ b/src/org/oscim/utils/GLSurfaceView.java
@@ -1,17 +1,3 @@
-/*
- * Copyright 2010, 2011, 2012 mapsforge.org
- *
- * This program is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
 package org.oscim.utils;
 
 /*
@@ -53,17 +39,21 @@ import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 
 /**
- * An implementation of SurfaceView that uses the dedicated surface for displaying OpenGL rendering.
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying OpenGL rendering.
  * <p>
  * A GLSurfaceView provides the following features:
  * <p>
  * <ul>
- * <li>Manages a surface, which is a special piece of memory that can be composited into the Android view system.
+ * <li>Manages a surface, which is a special piece of memory that can be
+ * composited into the Android view system.
  * <li>Manages an EGL display, which enables OpenGL to render into a surface.
  * <li>Accepts a user-provided Renderer object that does the actual rendering.
- * <li>Renders on a dedicated thread to decouple rendering performance from the UI thread.
+ * <li>Renders on a dedicated thread to decouple rendering performance from the
+ * UI thread.
  * <li>Supports both on-demand and continuous rendering.
- * <li>Optionally wraps, traces, and/or error-checks the renderer's OpenGL calls.
+ * <li>Optionally wraps, traces, and/or error-checks the renderer's OpenGL
+ * calls.
  * </ul>
  * <div class="special reference">
  * <h3>Developer Guides</h3>
@@ -73,15 +63,18 @@ import android.view.SurfaceView;
  * </p>
  * </div> <h3>Using GLSurfaceView</h3>
  * <p>
- * Typically you use GLSurfaceView by subclassing it and overriding one or more of the View system input event methods.
- * If your application does not need to override event methods then GLSurfaceView can be used as-is. For the most part
- * GLSurfaceView behavior is customized by calling "set" methods rather than by subclassing. For example, unlike a
- * regular View, drawing is delegated to a separate Renderer object which is registered with the GLSurfaceView using the
- * {@link #setRenderer(Renderer)} call.
+ * Typically you use GLSurfaceView by subclassing it and overriding one or more
+ * of the View system input event methods. If your application does not need to
+ * override event methods then GLSurfaceView can be used as-is. For the most
+ * part GLSurfaceView behavior is customized by calling "set" methods rather
+ * than by subclassing. For example, unlike a regular View, drawing is delegated
+ * to a separate Renderer object which is registered with the GLSurfaceView
+ * using the {@link #setRenderer(Renderer)} call.
  * <p>
- * <h3>Initializing GLSurfaceView</h3> All you have to do to initialize a GLSurfaceView is call
- * {@link #setRenderer(Renderer)}. However, if desired, you can modify the default behavior of GLSurfaceView by calling
- * one or more of these methods before calling setRenderer:
+ * <h3>Initializing GLSurfaceView</h3> All you have to do to initialize a
+ * GLSurfaceView is call {@link #setRenderer(Renderer)}. However, if desired,
+ * you can modify the default behavior of GLSurfaceView by calling one or more
+ * of these methods before calling setRenderer:
  * <ul>
  * <li>{@link #setDebugFlags(int)}
  * <li>{@link #setEGLConfigChooser(boolean)}
@@ -90,43 +83,54 @@ import android.view.SurfaceView;
  * <li>{@link #setGLWrapper(GLWrapper)}
  * </ul>
  * <p>
- * <h4>Specifying the android.view.Surface</h4> By default GLSurfaceView will create a PixelFormat.RGB_565 format
- * surface. If a translucent surface is required, call getHolder().setFormat(PixelFormat.TRANSLUCENT). The exact format
- * of a TRANSLUCENT surface is device dependent, but it will be a 32-bit-per-pixel surface with 8 bits per component.
+ * <h4>Specifying the android.view.Surface</h4> By default GLSurfaceView will
+ * create a PixelFormat.RGB_565 format surface. If a translucent surface is
+ * required, call getHolder().setFormat(PixelFormat.TRANSLUCENT). The exact
+ * format of a TRANSLUCENT surface is device dependent, but it will be a
+ * 32-bit-per-pixel surface with 8 bits per component.
  * <p>
- * <h4>Choosing an EGL Configuration</h4> A given Android device may support multiple EGLConfig rendering
- * configurations. The available configurations may differ in how may channels of data are present, as well as how many
- * bits are allocated to each channel. Therefore, the first thing GLSurfaceView has to do when starting to render is
- * choose what EGLConfig to use.
+ * <h4>Choosing an EGL Configuration</h4> A given Android device may support
+ * multiple EGLConfig rendering configurations. The available configurations may
+ * differ in how may channels of data are present, as well as how many bits are
+ * allocated to each channel. Therefore, the first thing GLSurfaceView has to do
+ * when starting to render is choose what EGLConfig to use.
  * <p>
- * By default GLSurfaceView chooses a EGLConfig that has an RGB_565 pixel format, with at least a 16-bit depth buffer
- * and no stencil.
+ * By default GLSurfaceView chooses a EGLConfig that has an RGB_565 pixel
+ * format, with at least a 16-bit depth buffer and no stencil.
  * <p>
- * If you would prefer a different EGLConfig you can override the default behavior by calling one of the
- * setEGLConfigChooser methods.
+ * If you would prefer a different EGLConfig you can override the default
+ * behavior by calling one of the setEGLConfigChooser methods.
  * <p>
- * <h4>Debug Behavior</h4> You can optionally modify the behavior of GLSurfaceView by calling one or more of the
- * debugging methods {@link #setDebugFlags(int)}, and {@link #setGLWrapper}. These methods may be called before and/or
- * after setRenderer, but typically they are called before setRenderer so that they take effect immediately.
+ * <h4>Debug Behavior</h4> You can optionally modify the behavior of
+ * GLSurfaceView by calling one or more of the debugging methods
+ * {@link #setDebugFlags(int)}, and {@link #setGLWrapper}. These methods may be
+ * called before and/or after setRenderer, but typically they are called before
+ * setRenderer so that they take effect immediately.
  * <p>
- * <h4>Setting a Renderer</h4> Finally, you must call {@link #setRenderer} to register a {@link Renderer}. The renderer
- * is responsible for doing the actual OpenGL rendering.
+ * <h4>Setting a Renderer</h4> Finally, you must call {@link #setRenderer} to
+ * register a {@link Renderer}. The renderer is responsible for doing the actual
+ * OpenGL rendering.
  * <p>
- * <h3>Rendering Mode</h3> Once the renderer is set, you can control whether the renderer draws continuously or
- * on-demand by calling {@link #setRenderMode}. The default is continuous rendering.
+ * <h3>Rendering Mode</h3> Once the renderer is set, you can control whether the
+ * renderer draws continuously or on-demand by calling {@link #setRenderMode}.
+ * The default is continuous rendering.
  * <p>
- * <h3>Activity Life-cycle</h3> A GLSurfaceView must be notified when the activity is paused and resumed. GLSurfaceView
- * clients are required to call {@link #onPause()} when the activity pauses and {@link #onResume()} when the activity
- * resumes. These calls allow GLSurfaceView to pause and resume the rendering thread, and also allow GLSurfaceView to
- * release and recreate the OpenGL display.
+ * <h3>Activity Life-cycle</h3> A GLSurfaceView must be notified when the
+ * activity is paused and resumed. GLSurfaceView clients are required to call
+ * {@link #onPause()} when the activity pauses and {@link #onResume()} when the
+ * activity resumes. These calls allow GLSurfaceView to pause and resume the
+ * rendering thread, and also allow GLSurfaceView to release and recreate the
+ * OpenGL display.
  * <p>
  * <h3>Handling events</h3>
  * <p>
- * To handle an event you will typically subclass GLSurfaceView and override the appropriate method, just as you would
- * with any other View. However, when handling the event, you may need to communicate with the Renderer object that's
- * running in the rendering thread. You can do this using any standard Java cross-thread communication mechanism. In
- * addition, one relatively easy way to communicate with your renderer is to call {@link #queueEvent(Runnable)}. For
- * example:
+ * To handle an event you will typically subclass GLSurfaceView and override the
+ * appropriate method, just as you would with any other View. However, when
+ * handling the event, you may need to communicate with the Renderer object
+ * that's running in the rendering thread. You can do this using any standard
+ * Java cross-thread communication mechanism. In addition, one relatively easy
+ * way to communicate with your renderer is to call
+ * {@link #queueEvent(Runnable)}. For example:
  * 
  * <pre class="prettyprint">
  * class MyGLSurfaceView extends GLSurfaceView {
@@ -154,9 +158,6 @@ import android.view.SurfaceView;
  * }
  * 
  * 
- * 
- * 
- * 
  * </pre>
  */
 public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
@@ -169,7 +170,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	private final static boolean LOG_RENDERER_DRAW_FRAME = false;
 	private final static boolean LOG_EGL = false;
 	/**
-	 * The renderer only renders when the surface is created, or when {@link #requestRender} is called.
+	 * The renderer only renders when the surface is created, or when
+	 * {@link #requestRender} is called.
 	 * 
 	 * @see #getRenderMode()
 	 * @see #setRenderMode(int)
@@ -185,8 +187,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	public final static int RENDERMODE_CONTINUOUSLY = 1;
 
 	/**
-	 * Check glError() after every GL call and throw an exception if glError indicates that an error has occurred. This
-	 * can be used to help track down which OpenGL ES call is causing an error.
+	 * Check glError() after every GL call and throw an exception if glError
+	 * indicates that an error has occurred. This can be used to help track down
+	 * which OpenGL ES call is causing an error.
 	 * 
 	 * @see #getDebugFlags
 	 * @see #setDebugFlags
@@ -194,7 +197,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	public final static int DEBUG_CHECK_GL_ERROR = 1;
 
 	/**
-	 * Log GL calls to the system log at "verbose" level with tag "GLSurfaceView".
+	 * Log GL calls to the system log at "verbose" level with tag
+	 * "GLSurfaceView".
 	 * 
 	 * @see #getDebugFlags
 	 * @see #setDebugFlags
@@ -202,8 +206,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	public final static int DEBUG_LOG_GL_CALLS = 2;
 
 	/**
-	 * Standard View constructor. In order to render something, you must call {@link #setRenderer} to register a
-	 * renderer.
+	 * Standard View constructor. In order to render something, you must call
+	 * {@link #setRenderer} to register a renderer.
+	 * 
+	 * @param context
+	 *            ...
 	 */
 	public GLSurfaceView(Context context) {
 		super(context);
@@ -211,8 +218,13 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Standard View constructor. In order to render something, you must call {@link #setRenderer} to register a
-	 * renderer.
+	 * Standard View constructor. In order to render something, you must call
+	 * {@link #setRenderer} to register a renderer.
+	 * 
+	 * @param context
+	 *            ....
+	 * @param attrs
+	 *            ...
 	 */
 	public GLSurfaceView(Context context, AttributeSet attrs) {
 		super(context, attrs);
@@ -247,9 +259,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Set the glWrapper. If the glWrapper is not null, its {@link GLWrapper#wrap(GL)} method is called whenever a
-	 * surface is created. A GLWrapper can be used to wrap the GL object that's passed to the renderer. Wrapping a GL
-	 * object enables examining and modifying the behavior of the GL calls made by the renderer.
+	 * Set the glWrapper. If the glWrapper is not null, its
+	 * {@link GLWrapper#wrap(GL)} method is called whenever a surface is
+	 * created. A GLWrapper can be used to wrap the GL object that's passed to
+	 * the renderer. Wrapping a GL object enables examining and modifying the
+	 * behavior of the GL calls made by the renderer.
 	 * <p>
 	 * Wrapping is typically used for debugging purposes.
 	 * <p>
@@ -263,8 +277,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Set the debug flags to a new value. The value is constructed by OR-together zero or more of the DEBUG_CHECK_*
-	 * constants. The debug flags take effect whenever a surface is created. The default value is zero.
+	 * Set the debug flags to a new value. The value is constructed by
+	 * OR-together zero or more of the DEBUG_CHECK_* constants. The debug flags
+	 * take effect whenever a surface is created. The default value is zero.
 	 * 
 	 * @param debugFlags
 	 *            the new debug flags
@@ -285,15 +300,18 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Control whether the EGL context is preserved when the GLSurfaceView is paused and resumed.
+	 * Control whether the EGL context is preserved when the GLSurfaceView is
+	 * paused and resumed.
 	 * <p>
-	 * If set to true, then the EGL context may be preserved when the GLSurfaceView is paused. Whether the EGL context
-	 * is actually preserved or not depends upon whether the Android device that the program is running on can support
-	 * an arbitrary number of EGL contexts or not. Devices that can only support a limited number of EGL contexts must
-	 * release the EGL context in order to allow multiple applications to share the GPU.
+	 * If set to true, then the EGL context may be preserved when the
+	 * GLSurfaceView is paused. Whether the EGL context is actually preserved or
+	 * not depends upon whether the Android device that the program is running
+	 * on can support an arbitrary number of EGL contexts or not. Devices that
+	 * can only support a limited number of EGL contexts must release the EGL
+	 * context in order to allow multiple applications to share the GPU.
 	 * <p>
-	 * If set to false, the EGL context will be released when the GLSurfaceView is paused, and recreated when the
-	 * GLSurfaceView is resumed.
+	 * If set to false, the EGL context will be released when the GLSurfaceView
+	 * is paused, and recreated when the GLSurfaceView is resumed.
 	 * <p>
 	 * The default is false.
 	 * 
@@ -312,19 +330,22 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Set the renderer associated with this view. Also starts the thread that will call the renderer, which in turn
-	 * causes the rendering to start.
+	 * Set the renderer associated with this view. Also starts the thread that
+	 * will call the renderer, which in turn causes the rendering to start.
 	 * <p>
-	 * This method should be called once and only once in the life-cycle of a GLSurfaceView.
+	 * This method should be called once and only once in the life-cycle of a
+	 * GLSurfaceView.
 	 * <p>
-	 * The following GLSurfaceView methods can only be called <em>before</em> setRenderer is called:
+	 * The following GLSurfaceView methods can only be called <em>before</em>
+	 * setRenderer is called:
 	 * <ul>
 	 * <li>{@link #setEGLConfigChooser(boolean)}
 	 * <li>{@link #setEGLConfigChooser(EGLConfigChooser)}
 	 * <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)}
 	 * </ul>
 	 * <p>
-	 * The following GLSurfaceView methods can only be called <em>after</em> setRenderer is called:
+	 * The following GLSurfaceView methods can only be called <em>after</em>
+	 * setRenderer is called:
 	 * <ul>
 	 * <li>{@link #getRenderMode()}
 	 * <li>{@link #onPause()}
@@ -356,10 +377,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	/**
 	 * Install a custom EGLContextFactory.
 	 * <p>
-	 * If this method is called, it must be called before {@link #setRenderer(Renderer)} is called.
+	 * If this method is called, it must be called before
+	 * {@link #setRenderer(Renderer)} is called.
 	 * <p>
-	 * If this method is not called, then by default a context will be created with no shared context and with a null
-	 * attribute list.
+	 * If this method is not called, then by default a context will be created
+	 * with no shared context and with a null attribute list.
 	 */
 	public void setEGLContextFactory(EGLContextFactory factory) {
 		checkRenderThreadState();
@@ -369,9 +391,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	/**
 	 * Install a custom EGLWindowSurfaceFactory.
 	 * <p>
-	 * If this method is called, it must be called before {@link #setRenderer(Renderer)} is called.
+	 * If this method is called, it must be called before
+	 * {@link #setRenderer(Renderer)} is called.
 	 * <p>
-	 * If this method is not called, then by default a window surface will be created with a null attribute list.
+	 * If this method is not called, then by default a window surface will be
+	 * created with a null attribute list.
 	 */
 	public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {
 		checkRenderThreadState();
@@ -381,10 +405,12 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	/**
 	 * Install a custom EGLConfigChooser.
 	 * <p>
-	 * If this method is called, it must be called before {@link #setRenderer(Renderer)} is called.
+	 * If this method is called, it must be called before
+	 * {@link #setRenderer(Renderer)} is called.
 	 * <p>
-	 * If no setEGLConfigChooser method is called, then by default the view will choose an EGLConfig that is compatible
-	 * with the current android.view.Surface, with a depth buffer depth of at least 16 bits.
+	 * If no setEGLConfigChooser method is called, then by default the view will
+	 * choose an EGLConfig that is compatible with the current
+	 * android.view.Surface, with a depth buffer depth of at least 16 bits.
 	 * 
 	 * @param configChooser
 	 */
@@ -394,13 +420,15 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Install a config chooser which will choose a config as close to 16-bit RGB as possible, with or without an
-	 * optional depth buffer as close to 16-bits as possible.
+	 * Install a config chooser which will choose a config as close to 16-bit
+	 * RGB as possible, with or without an optional depth buffer as close to
+	 * 16-bits as possible.
 	 * <p>
-	 * If this method is called, it must be called before {@link #setRenderer(Renderer)} is called.
+	 * If this method is called, it must be called before
+	 * {@link #setRenderer(Renderer)} is called.
 	 * <p>
-	 * If no setEGLConfigChooser method is called, then by default the view will choose an RGB_565 surface with a depth
-	 * buffer depth of at least 16 bits.
+	 * If no setEGLConfigChooser method is called, then by default the view will
+	 * choose an RGB_565 surface with a depth buffer depth of at least 16 bits.
 	 * 
 	 * @param needDepth
 	 */
@@ -409,13 +437,15 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Install a config chooser which will choose a config with at least the specified depthSize and stencilSize, and
-	 * exactly the specified redSize, greenSize, blueSize and alphaSize.
+	 * Install a config chooser which will choose a config with at least the
+	 * specified depthSize and stencilSize, and exactly the specified redSize,
+	 * greenSize, blueSize and alphaSize.
 	 * <p>
-	 * If this method is called, it must be called before {@link #setRenderer(Renderer)} is called.
+	 * If this method is called, it must be called before
+	 * {@link #setRenderer(Renderer)} is called.
 	 * <p>
-	 * If no setEGLConfigChooser method is called, then by default the view will choose an RGB_565 surface with a depth
-	 * buffer depth of at least 16 bits.
+	 * If no setEGLConfigChooser method is called, then by default the view will
+	 * choose an RGB_565 surface with a depth buffer depth of at least 16 bits.
 	 */
 	public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
 			int alphaSize, int depthSize, int stencilSize) {
@@ -424,7 +454,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Inform the default EGLContextFactory and default EGLConfigChooser which EGLContext client version to pick.
+	 * Inform the default EGLContextFactory and default EGLConfigChooser which
+	 * EGLContext client version to pick.
 	 * <p>
 	 * Use this method to create an OpenGL ES 2.0-compatible context. Example:
 	 * 
@@ -436,19 +467,24 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	 * }
 	 * </pre>
 	 * <p>
-	 * Note: Activities which require OpenGL ES 2.0 should indicate this by setting @lt;uses-feature
-	 * android:glEsVersion="0x00020000" /> in the activity's AndroidManifest.xml file.
+	 * Note: Activities which require OpenGL ES 2.0 should indicate this by
+	 * setting @lt;uses-feature android:glEsVersion="0x00020000" /> in the
+	 * activity's AndroidManifest.xml file.
 	 * <p>
-	 * If this method is called, it must be called before {@link #setRenderer(Renderer)} is called.
+	 * If this method is called, it must be called before
+	 * {@link #setRenderer(Renderer)} is called.
 	 * <p>
-	 * This method only affects the behavior of the default EGLContexFactory and the default EGLConfigChooser. If
-	 * {@link #setEGLContextFactory(EGLContextFactory)} has been called, then the supplied EGLContextFactory is
-	 * responsible for creating an OpenGL ES 2.0-compatible context. If {@link #setEGLConfigChooser(EGLConfigChooser)}
-	 * has been called, then the supplied EGLConfigChooser is responsible for choosing an OpenGL ES 2.0-compatible
-	 * config.
+	 * This method only affects the behavior of the default EGLContexFactory and
+	 * the default EGLConfigChooser. If
+	 * {@link #setEGLContextFactory(EGLContextFactory)} has been called, then
+	 * the supplied EGLContextFactory is responsible for creating an OpenGL ES
+	 * 2.0-compatible context. If {@link #setEGLConfigChooser(EGLConfigChooser)}
+	 * has been called, then the supplied EGLConfigChooser is responsible for
+	 * choosing an OpenGL ES 2.0-compatible config.
 	 * 
 	 * @param version
-	 *            The EGLContext client version to choose. Use 2 for OpenGL ES 2.0
+	 *            The EGLContext client version to choose. Use 2 for OpenGL ES
+	 *            2.0
 	 */
 	public void setEGLContextClientVersion(int version) {
 		checkRenderThreadState();
@@ -456,12 +492,15 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Set the rendering mode. When renderMode is RENDERMODE_CONTINUOUSLY, the renderer is called repeatedly to
-	 * re-render the scene. When renderMode is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface is
-	 * created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY.
+	 * Set the rendering mode. When renderMode is RENDERMODE_CONTINUOUSLY, the
+	 * renderer is called repeatedly to re-render the scene. When renderMode is
+	 * RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface is
+	 * created, or when {@link #requestRender} is called. Defaults to
+	 * RENDERMODE_CONTINUOUSLY.
 	 * <p>
-	 * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance by allowing the GPU and CPU
-	 * to idle when the view does not need to be updated.
+	 * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system
+	 * performance by allowing the GPU and CPU to idle when the view does not
+	 * need to be updated.
 	 * <p>
 	 * This method can only be called after {@link #setRenderer(Renderer)}
 	 * 
@@ -475,7 +514,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Get the current rendering mode. May be called from any thread. Must not be called before a renderer has been set.
+	 * Get the current rendering mode. May be called from any thread. Must not
+	 * be called before a renderer has been set.
 	 * 
 	 * @return the current rendering mode.
 	 * @see #RENDERMODE_CONTINUOUSLY
@@ -486,25 +526,26 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Request that the renderer render a frame. This method is typically used when the render mode has been set to
-	 * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand. May be called from any thread. Must
-	 * not be called before a renderer has been set.
+	 * Request that the renderer render a frame. This method is typically used
+	 * when the render mode has been set to {@link #RENDERMODE_WHEN_DIRTY}, so
+	 * that frames are only rendered on demand. May be called from any thread.
+	 * Must not be called before a renderer has been set.
 	 */
 	public void requestRender() {
 		mGLThread.requestRender();
 	}
 
 	/**
-	 * This method is part of the SurfaceHolder.Callback interface, and is not normally called or subclassed by clients
-	 * of GLSurfaceView.
+	 * This method is part of the SurfaceHolder.Callback interface, and is not
+	 * normally called or subclassed by clients of GLSurfaceView.
 	 */
 	public void surfaceCreated(SurfaceHolder holder) {
 		mGLThread.surfaceCreated();
 	}
 
 	/**
-	 * This method is part of the SurfaceHolder.Callback interface, and is not normally called or subclassed by clients
-	 * of GLSurfaceView.
+	 * This method is part of the SurfaceHolder.Callback interface, and is not
+	 * normally called or subclassed by clients of GLSurfaceView.
 	 */
 	public void surfaceDestroyed(SurfaceHolder holder) {
 		// Surface will be destroyed when we return
@@ -512,33 +553,37 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * This method is part of the SurfaceHolder.Callback interface, and is not normally called or subclassed by clients
-	 * of GLSurfaceView.
+	 * This method is part of the SurfaceHolder.Callback interface, and is not
+	 * normally called or subclassed by clients of GLSurfaceView.
 	 */
 	public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
 		mGLThread.onWindowResize(w, h);
 	}
 
 	/**
-	 * Inform the view that the activity is paused. The owner of this view must call this method when the activity is
-	 * paused. Calling this method will pause the rendering thread. Must not be called before a renderer has been set.
+	 * Inform the view that the activity is paused. The owner of this view must
+	 * call this method when the activity is paused. Calling this method will
+	 * pause the rendering thread. Must not be called before a renderer has been
+	 * set.
 	 */
 	public void onPause() {
 		mGLThread.onPause();
 	}
 
 	/**
-	 * Inform the view that the activity is resumed. The owner of this view must call this method when the activity is
-	 * resumed. Calling this method will recreate the OpenGL display and resume the rendering thread. Must not be called
-	 * before a renderer has been set.
+	 * Inform the view that the activity is resumed. The owner of this view must
+	 * call this method when the activity is resumed. Calling this method will
+	 * recreate the OpenGL display and resume the rendering thread. Must not be
+	 * called before a renderer has been set.
 	 */
 	public void onResume() {
 		mGLThread.onResume();
 	}
 
 	/**
-	 * Queue a runnable to be run on the GL rendering thread. This can be used to communicate with the Renderer on the
-	 * rendering thread. Must not be called before a renderer has been set.
+	 * Queue a runnable to be run on the GL rendering thread. This can be used
+	 * to communicate with the Renderer on the rendering thread. Must not be
+	 * called before a renderer has been set.
 	 * 
 	 * @param r
 	 *            the runnable to be run on the GL rendering thread.
@@ -548,8 +593,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * This method is used as part of the View class and is not normally called or subclassed by clients of
-	 * GLSurfaceView.
+	 * This method is used as part of the View class and is not normally called
+	 * or subclassed by clients of GLSurfaceView.
 	 */
 	@Override
 	protected void onAttachedToWindow() {
@@ -572,8 +617,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * This method is used as part of the View class and is not normally called or subclassed by clients of
-	 * GLSurfaceView. Must not be called before a renderer has been set.
+	 * This method is used as part of the View class and is not normally called
+	 * or subclassed by clients of GLSurfaceView. Must not be called before a
+	 * renderer has been set.
 	 */
 	@Override
 	protected void onDetachedFromWindow() {
@@ -592,10 +638,12 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	/**
 	 * An interface used to wrap a GL interface.
 	 * <p>
-	 * Typically used for implementing debugging and tracing on top of the default GL interface. You would typically use
-	 * this by creating your own class that implemented all the GL methods by delegating to another GL instance. Then
-	 * you could add your own behavior before or after calling the delegate. All the GLWrapper would do was instantiate
-	 * and return the wrapper GL instance:
+	 * Typically used for implementing debugging and tracing on top of the
+	 * default GL interface. You would typically use this by creating your own
+	 * class that implemented all the GL methods by delegating to another GL
+	 * instance. Then you could add your own behavior before or after calling
+	 * the delegate. All the GLWrapper would do was instantiate and return the
+	 * wrapper GL instance:
 	 * 
 	 * <pre class="prettyprint">
 	 * class MyGLWrapper implements GLWrapper {
@@ -616,13 +664,15 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		 * 
 		 * @param gl
 		 *            a GL interface that is to be wrapped.
-		 * @return either the input argument or another GL object that wraps the input argument.
+		 * @return either the input argument or another GL object that wraps the
+		 *         input argument.
 		 */
 		GL wrap(GL gl);
 	}
 
 	/**
-	 * An interface for customizing the eglCreateContext and eglDestroyContext calls.
+	 * An interface for customizing the eglCreateContext and eglDestroyContext
+	 * calls.
 	 * <p>
 	 * This interface must be implemented by clients wishing to call
 	 * {@link GLSurfaceView#setEGLContextFactory(EGLContextFactory)}
@@ -633,9 +683,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
 	}
 
-	private class DefaultContextFactory implements EGLContextFactory {
+	private final class DefaultContextFactory implements EGLContextFactory {
 		private int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
 
+		@Override
 		public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
 			int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
 					EGL10.EGL_NONE };
@@ -644,6 +695,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 					mEGLContextClientVersion != 0 ? attrib_list : null);
 		}
 
+		@Override
 		public void destroyContext(EGL10 egl, EGLDisplay display,
 				EGLContext context) {
 			if (!egl.eglDestroyContext(display, context)) {
@@ -659,13 +711,22 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls.
+	 * An interface for customizing the eglCreateWindowSurface and
+	 * eglDestroySurface calls.
 	 * <p>
 	 * This interface must be implemented by clients wishing to call
 	 * {@link GLSurfaceView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
 	 */
 	public interface EGLWindowSurfaceFactory {
 		/**
+		 * @param egl
+		 *            ...
+		 * @param display
+		 *            ...
+		 * @param config
+		 *            ...
+		 * @param nativeWindow
+		 *            ...
 		 * @return null if the surface cannot be constructed.
 		 */
 		EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,
@@ -676,6 +737,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 
 	private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
 
+		@Override
 		public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
 				EGLConfig config, Object nativeWindow) {
 			EGLSurface result = null;
@@ -683,7 +745,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 				result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
 			} catch (IllegalArgumentException e) {
 				// This exception indicates that the surface flinger surface
-				// is not valid. This can happen if the surface flinger surface has
+				// is not valid. This can happen if the surface flinger surface
+				// has
 				// been torn down, but the application has not yet been
 				// notified via SurfaceHolder.Callback.surfaceDestroyed.
 				// In theory the application should be notified first,
@@ -693,6 +756,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 			return result;
 		}
 
+		@Override
 		public void destroySurface(EGL10 egl, EGLDisplay display,
 				EGLSurface surface) {
 			egl.eglDestroySurface(display, surface);
@@ -705,6 +769,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 			mConfigSpec = filterConfigSpec(configSpec);
 		}
 
+		@Override
 		public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
 			int[] num_config = new int[1];
 			if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
@@ -741,7 +806,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 				return configSpec;
 			}
 			/*
-			 * We know none of the subclasses define EGL_RENDERABLE_TYPE. And we know the configSpec is well formed.
+			 * We know none of the subclasses define EGL_RENDERABLE_TYPE. And we
+			 * know the configSpec is well formed.
 			 */
 			int len = configSpec.length;
 			int[] newConfigSpec = new int[len + 2];
@@ -754,8 +820,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * Choose a configuration with exactly the specified r,g,b,a sizes, and at least the specified depth and stencil
-	 * sizes.
+	 * Choose a configuration with exactly the specified r,g,b,a sizes, and at
+	 * least the specified depth and stencil sizes.
 	 */
 	private class ComponentSizeChooser extends BaseConfigChooser {
 		public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
@@ -842,8 +908,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 
 		/**
 		 * Initialize EGL for a given configuration spec.
-		 * 
-		 * @param configSpec
 		 */
 		public void start() {
 			if (LOG_EGL) {
@@ -878,8 +942,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 				mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
 
 				/*
-				 * Create an EGL context. We want to do this as rarely as we can, because an EGL context is a somewhat
-				 * heavy object.
+				 * Create an EGL context. We want to do this as rarely as we
+				 * can, because an EGL context is a somewhat heavy object.
 				 */
 				mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay,
 						mEglConfig);
@@ -897,8 +961,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		}
 
 		/**
-		 * Create an egl surface for the current SurfaceHolder surface. If a surface already exists, destroy it before
-		 * creating the new surface.
+		 * Create an egl surface for the current SurfaceHolder surface. If a
+		 * surface already exists, destroy it before creating the new surface.
 		 * 
 		 * @return true if the surface was created successfully.
 		 */
@@ -946,12 +1010,13 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 			}
 
 			/*
-			 * Before we can issue GL commands, we need to make sure the context is current and bound to a surface.
+			 * Before we can issue GL commands, we need to make sure the context
+			 * is current and bound to a surface.
 			 */
 			if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
 				/*
-				 * Could not make the context current, probably because the underlying SurfaceView surface has been
-				 * destroyed.
+				 * Could not make the context current, probably because the
+				 * underlying SurfaceView surface has been destroyed.
 				 */
 				logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
 				return false;
@@ -963,7 +1028,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		/**
 		 * Create a GL object for the current EGL context.
 		 * 
-		 * @return
+		 * @return ...
 		 */
 		GL createGL() {
 
@@ -1060,7 +1125,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		}
 
 		public static String formatEglError(String function, int error) {
-			return function + " failed: "; // + EGLLogWrapper.getErrorString(error);
+			return function + " failed: "; // +
+											// EGLLogWrapper.getErrorString(error);
 		}
 
 		private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
@@ -1073,9 +1139,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 	}
 
 	/**
-	 * A generic GL Thread. Takes care of initializing EGL and GL. Delegates to a Renderer instance to do the actual
-	 * drawing. Can be configured to render continuously or on request. All potentially blocking synchronization is done
-	 * through the sGLThreadManager object. This avoids multiple-lock ordering issues.
+	 * A generic GL Thread. Takes care of initializing EGL and GL. Delegates to
+	 * a Renderer instance to do the actual drawing. Can be configured to render
+	 * continuously or on request. All potentially blocking synchronization is
+	 * done through the sGLThreadManager object. This avoids multiple-lock
+	 * ordering issues.
 	 */
 	static class GLThread extends Thread {
 		GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
@@ -1104,7 +1172,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		}
 
 		/*
-		 * This private method should only be called inside a synchronized(sGLThreadManager) block.
+		 * This private method should only be called inside a
+		 * synchronized(sGLThreadManager) block.
 		 */
 		private void stopEglSurfaceLocked() {
 			if (mHaveEglSurface) {
@@ -1114,7 +1183,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		}
 
 		/*
-		 * This private method should only be called inside a synchronized(sGLThreadManager) block.
+		 * This private method should only be called inside a
+		 * synchronized(sGLThreadManager) block.
 		 */
 		private void stopEglContextLocked() {
 			if (mHaveEglContext) {
@@ -1265,7 +1335,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 							// Ready to draw?
 							if (readyToDraw()) {
 
-								// If we don't have an EGL context, try to acquire one.
+								// If we don't have an EGL context, try to
+								// acquire one.
 								if (!mHaveEglContext) {
 									if (askedToReleaseEglContext) {
 										askedToReleaseEglContext = false;
@@ -1315,7 +1386,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 								}
 							}
 
-							// By design, this is the only place in a GLThread thread where we wait().
+							// By design, this is the only place in a GLThread
+							// thread where we wait().
 							if (LOG_THREADS) {
 								Log.i("GLThread", "waiting tid=" + getId()
 										+ " mHaveEglContext: " + mHaveEglContext
@@ -1402,10 +1474,13 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 							lostEglContext = true;
 							break;
 						default:
-							// Other errors typically mean that the current surface is bad,
-							// probably because the SurfaceView surface has been destroyed,
+							// Other errors typically mean that the current
+							// surface is bad,
+							// probably because the SurfaceView surface has been
+							// destroyed,
 							// but we haven't been notified yet.
-							// Log the error to help developers understand why rendering stopped.
+							// Log the error to help developers understand why
+							// rendering stopped.
 							EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers",
 									swapError);
 
@@ -1629,8 +1704,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		private EglHelper mEglHelper;
 
 		/**
-		 * Set once at thread construction time, nulled out when the parent view is garbage called. This weak reference
-		 * allows the GLSurfaceView to be garbage collected while the GLThread is still alive.
+		 * Set once at thread construction time, nulled out when the parent view
+		 * is garbage called. This weak reference allows the GLSurfaceView to be
+		 * garbage collected while the GLThread is still alive.
 		 */
 		private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
 
@@ -1693,8 +1769,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		}
 
 		/*
-		 * Tries once to acquire the right to use an EGL context. Does not block. Requires that we are already in the
-		 * sGLThreadManager monitor when this is called.
+		 * Tries once to acquire the right to use an EGL context. Does not
+		 * block. Requires that we are already in the sGLThreadManager monitor
+		 * when this is called.
 		 * @return true if the right to use an EGL context was acquired.
 		 */
 		public boolean tryAcquireEglContextLocked(GLThread thread) {
@@ -1718,7 +1795,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		}
 
 		/*
-		 * Releases the EGL context. Requires that we are already in the sGLThreadManager monitor when this is called.
+		 * Releases the EGL context. Requires that we are already in the
+		 * sGLThreadManager monitor when this is called.
 		 */
 		public void releaseEglContextLocked(GLThread thread) {
 			if (mEglOwner == thread) {
@@ -1777,8 +1855,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		}
 
 		/**
-		 * This check was required for some pre-Android-3.0 hardware. Android 3.0 provides support for
-		 * hardware-accelerated views, therefore multiple EGL contexts are supported on all Android 3.0+ EGL drivers.
+		 * This check was required for some pre-Android-3.0 hardware. Android
+		 * 3.0 provides support for hardware-accelerated views, therefore
+		 * multiple EGL contexts are supported on all Android 3.0+ EGL drivers.
 		 */
 		private boolean mGLESVersionCheckComplete;
 		private int mGLESVersion;
@@ -1791,7 +1870,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
 		private GLThread mEglOwner;
 	}
 
-	private static final GLThreadManager sGLThreadManager = new GLThreadManager();
+	/* package */static final GLThreadManager sGLThreadManager = new GLThreadManager();
 
 	private final WeakReference<GLSurfaceView> mThisWeakRef =
 			new WeakReference<GLSurfaceView>(this);
diff --git a/src/org/oscim/view/MapActivity.java b/src/org/oscim/view/MapActivity.java
index 7300a176..d4c2753d 100644
--- a/src/org/oscim/view/MapActivity.java
+++ b/src/org/oscim/view/MapActivity.java
@@ -17,7 +17,6 @@ package org.oscim.view;
 import java.io.FileNotFoundException;
 
 import org.oscim.core.GeoPoint;
-import org.oscim.core.MapPosition;
 import org.oscim.theme.InternalRenderTheme;
 
 import android.app.Activity;
diff --git a/src/org/oscim/core/MapPosition.java b/src/org/oscim/view/MapPosition.java
similarity index 83%
rename from src/org/oscim/core/MapPosition.java
rename to src/org/oscim/view/MapPosition.java
index 7b81bb1a..94d60e7b 100644
--- a/src/org/oscim/core/MapPosition.java
+++ b/src/org/oscim/view/MapPosition.java
@@ -12,34 +12,29 @@
  * You should have received a copy of the GNU Lesser General Public License along with
  * this program. If not, see <http://www.gnu.org/licenses/>.
  */
-package org.oscim.core;
+package org.oscim.view;
+
+import org.oscim.core.GeoPoint;
+import org.oscim.core.MercatorProjection;
+
+import android.opengl.Matrix;
 
 /**
- * A MapPosition represents an immutable pair of {@link GeoPoint} and zoom level.
+ * A MapPosition Container.
  */
 public class MapPosition {
 
-	/**
-	 * The map position.
-	 */
-	// public final GeoPoint geoPoint;
-	public final double lon;
-	public final double lat;
+	public double lon;
+	public double lat;
 
-	/**
-	 * The zoom level.
-	 */
-	public final byte zoomLevel;
+	public byte zoomLevel;
+	public float scale;
+	public float angle;
 
-	/**
-	 * 1.0 - 2.0 scale of current zoomlevel
-	 */
-	public final float scale;
+	public double x;
+	public double y;
 
-	public final float angle;
-
-	public final double x;
-	public final double y;
+	public float[] rotation;
 
 	public MapPosition() {
 		this.zoomLevel = (byte) 1;
@@ -51,6 +46,11 @@ public class MapPosition {
 		this.y = MercatorProjection.latitudeToPixelY(this.lat, zoomLevel);
 	}
 
+	public void init() {
+		rotation = new float[16];
+		Matrix.setIdentityM(rotation, 0);
+	}
+
 	/**
 	 * @param geoPoint
 	 *            the map position.
diff --git a/src/org/oscim/view/MapScaleBar.java b/src/org/oscim/view/MapScaleBar.java
index 39915c45..45dada8e 100644
--- a/src/org/oscim/view/MapScaleBar.java
+++ b/src/org/oscim/view/MapScaleBar.java
@@ -17,7 +17,6 @@ package org.oscim.view;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.oscim.core.MapPosition;
 import org.oscim.core.MercatorProjection;
 
 import android.graphics.Bitmap;
diff --git a/src/org/oscim/view/MapView.java b/src/org/oscim/view/MapView.java
index 06cf09ca..b65b5fd4 100644
--- a/src/org/oscim/view/MapView.java
+++ b/src/org/oscim/view/MapView.java
@@ -23,7 +23,6 @@ import java.util.Map;
 import javax.xml.parsers.ParserConfigurationException;
 
 import org.oscim.core.GeoPoint;
-import org.oscim.core.MapPosition;
 import org.oscim.core.Tile;
 import org.oscim.database.IMapDatabase;
 import org.oscim.database.MapDatabaseFactory;
@@ -56,9 +55,9 @@ public class MapView extends FrameLayout {
 
 	final static String TAG = "MapView";
 
-	public final static boolean debugFrameTime = false;
-	public final static boolean testRegionZoom = false;
-	private final boolean mDebugDatabase = false;
+	public static final boolean debugFrameTime = false;
+	public static final boolean testRegionZoom = false;
+	private static final boolean debugDatabase = false;
 
 	RegionLookup mRegionLookup;
 
@@ -146,7 +145,7 @@ public class MapView extends FrameLayout {
 
 		for (int i = 0; i < mNumMapWorkers; i++) {
 			IMapDatabase mapDatabase;
-			if (mDebugDatabase) {
+			if (debugDatabase) {
 				// mapDatabase = MapDatabaseFactory
 				// .createMapDatabase(MapDatabases.TEST_READER);
 				mapDatabase = MapDatabaseFactory
@@ -188,7 +187,7 @@ public class MapView extends FrameLayout {
 		mMapZoomControls = new MapZoomControls(mapActivity, this);
 		mMapZoomControls.setShowMapZoomControls(true);
 
-		// enableRotation = true;
+		enableRotation = true;
 
 		for (MapWorker worker : mMapWorkers)
 			worker.start();
@@ -353,7 +352,7 @@ public class MapView extends FrameLayout {
 	 */
 
 	public void setMapDatabase(MapDatabases mapDatabaseType) {
-		if (mDebugDatabase)
+		if (debugDatabase)
 			return;
 
 		TileGenerator tileGenerator;
@@ -470,6 +469,9 @@ public class MapView extends FrameLayout {
 		Log.d(TAG, "onSizeChanged" + width + " " + height);
 		super.onSizeChanged(width, height, oldWidth, oldHeight);
 
+		if (width != 0 && height != 0)
+			mMapViewPosition.setViewport(width, height);
+
 		mapWorkersProceed();
 	}
 
diff --git a/src/org/oscim/view/MapViewPosition.java b/src/org/oscim/view/MapViewPosition.java
index 387b5108..e463dc78 100644
--- a/src/org/oscim/view/MapViewPosition.java
+++ b/src/org/oscim/view/MapViewPosition.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010, 2011, 2012 mapsforge.org
+ * Copyright 2010, 2011, 2012 mapsforge.org, 2012 Hannes Janetzek
  *
  * This program is free software: you can redistribute it and/or modify it under the
  * terms of the GNU Lesser General Public License as published by the Free Software
@@ -15,36 +15,36 @@
 package org.oscim.view;
 
 import org.oscim.core.GeoPoint;
-import org.oscim.core.MapPosition;
 import org.oscim.core.MercatorProjection;
 import org.oscim.utils.FastMath;
 
+import android.opengl.Matrix;
+import android.util.FloatMath;
+import android.util.Log;
+
 /**
  * A MapPosition stores the latitude and longitude coordinate of a MapView
  * together with its zoom level.
  */
 public class MapViewPosition {
-	private static final String TAG = "MapViewPosition";
+	// private static final String TAG = "MapViewPosition";
 
-	public final static int MAX_ZOOMLEVEL = 16;
+	public final static int MAX_ZOOMLEVEL = 17;
 
-	private final static float MAX_SCALE = 2.0f;
-	private final static float MIN_SCALE = 1.0f;
+	private final static float MAX_ANGLE = 20;
 
 	private final MapView mMapView;
 
 	private double mLatitude;
 	private double mLongitude;
 	private byte mZoomLevel;
+	// 1.0 - 2.0 scale per level
 	private float mScale;
-	private float mRotation;
-	public float mTilt;
-
 	// 2^mZoomLevel * mScale;
 	private float mMapScale;
 
-	// private final static float MAP_SIZE = 1000000;
-	// private final static float MAP_SIZE2 = 1000000 >> 1;
+	private float mRotation;
+	public float mTilt;
 
 	MapViewPosition(MapView mapView) {
 		mMapView = mapView;
@@ -58,20 +58,158 @@ public class MapViewPosition {
 		mMapScale = 1;
 	}
 
-	// private static double latitudeToMapView(double latitude) {
-	// double sinLatitude = Math.sin(latitude * (Math.PI / 180));
-	// return (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 *
-	// Math.PI))
-	// * MAP_SIZE;
-	// }
-	//
-	// public static double longitudeToMapView(double longitude) {
-	// return (longitude + 180) / 360 * MAP_SIZE;
-	// }
-	//
-	// private static double pixelXToLongitude(double pixelX, byte zoomLevel) {
-	// return 360 * ((pixelX / ((long) Tile.TILE_SIZE << zoomLevel)) - 0.5);
-	// }
+	private float[] mProjMatrix = new float[16];
+	private float[] mProjMatrixI = new float[16];
+	private float[] mUnprojMatrix = new float[16];
+	private float[] mRotateMatrix = new float[16];
+	private float[] mTmpMatrix = new float[16];
+
+	private int mHeight, mWidth;
+
+	void setViewport(int width, int height) {
+		Matrix.frustumM(mProjMatrix, 0, -0.5f * width, 0.5f * width,
+				-0.5f * height, 0.5f * height, 1, 2);
+
+		Matrix.translateM(mProjMatrix, 0, 0, 0, -1);
+
+		Matrix.invertM(mProjMatrixI, 0, mProjMatrix, 0);
+		Matrix.invertM(mUnprojMatrix, 0, mProjMatrix, 0);
+
+		Matrix.setIdentityM(mRotateMatrix, 0);
+
+		mHeight = height;
+		mWidth = width;
+	}
+
+	public synchronized boolean getMapPosition(final MapPosition mapPosition,
+			final float[] coords) {
+		// if (!isValid())
+		// return false;
+
+		// if (mapPosition.lat == mLatitude
+		// && mapPosition.lon == mLongitude
+		// && mapPosition.zoomLevel == mZoomLevel
+		// && mapPosition.scale == mScale
+		// && mapPosition.angle == mRotation)
+		// return false;
+
+		mapPosition.lat = mLatitude;
+		mapPosition.lon = mLongitude;
+		mapPosition.angle = mRotation;
+		mapPosition.zoomLevel = mZoomLevel;
+		mapPosition.scale = mScale;
+		byte z = mZoomLevel;
+		mapPosition.x = MercatorProjection.longitudeToPixelX(mLongitude, z);
+		mapPosition.y = MercatorProjection.latitudeToPixelY(mLatitude, z);
+
+		if (mapPosition.rotation != null) {
+			// updateMatrix();
+			System.arraycopy(mRotateMatrix, 0, mapPosition.rotation, 0, 16);
+		}
+
+		if (coords == null)
+			return true;
+
+		// if (mapPosition.rotation == null)
+		// updateMatrix();
+
+		// not so sure about this, but works...
+		float tilt = FloatMath.sin((float) Math.toRadians(mTilt)) * 4;
+
+		unproject(-1, 1, tilt, coords, 0); // top-left
+		unproject(1, 1, tilt, coords, 2); // top-right
+		unproject(1, -1, -tilt, coords, 4); // bottom-right
+		unproject(-1, -1, -tilt, coords, 6); // bottom-left
+
+		return true;
+	}
+
+	private float[] mv = { 0, 0, 0, 1 };
+	private float[] mBBoxCoords = new float[8];
+
+	private void unproject(float x, float y, float z, float[] coords, int position) {
+		mv[0] = x;
+		mv[1] = y;
+		mv[2] = z - 1;
+		mv[3] = 1;
+
+		Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0);
+
+		if (mv[3] != 0) {
+			float w = 1 / mv[3];
+			float xx = mv[0] * w;
+			float yy = mv[1] * w;
+
+			coords[position] = xx;
+			coords[position + 1] = yy;
+		}
+		// else what?
+	}
+
+	private void updateMatrix() {
+		Matrix.setRotateM(mRotateMatrix, 0, mRotation, 0, 0, 1);
+
+		// tilt map
+		float tilt = mTilt;
+		Matrix.setRotateM(mTmpMatrix, 0, -tilt / (mHeight / 2), 1, 0, 0);
+
+		// apply first rotation, then tilt
+		Matrix.multiplyMM(mRotateMatrix, 0, mTmpMatrix, 0, mRotateMatrix, 0);
+
+		// get unproject matrix:
+		// (transpose of rotation is its inverse)
+		Matrix.transposeM(mTmpMatrix, 0, mRotateMatrix, 0);
+		// (AB)^-1 = B^-1*A^-1
+		Matrix.multiplyMM(mUnprojMatrix, 0, mTmpMatrix, 0, mProjMatrixI, 0);
+
+	}
+
+	/**
+	 * sets viewBox to visible bounding box, (left,top,right,bottom)
+	 * 
+	 * @param viewBox
+	 *            ...
+	 */
+	public synchronized void getViewBox(final float[] viewBox) {
+
+		updateMatrix();
+
+		float tilt = FloatMath.sin((float) Math.toRadians(mTilt)) * 4;
+
+		unproject(-1, 1, tilt, mBBoxCoords, 0); // top-left
+		unproject(1, 1, tilt, mBBoxCoords, 2); // top-right
+		unproject(1, -1, -tilt, mBBoxCoords, 4); // bottom-right
+		unproject(-1, -1, -tilt, mBBoxCoords, 6); // bottom-left
+
+		byte z = mZoomLevel;
+		double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, z);
+		double pixelY = MercatorProjection.latitudeToPixelY(mLatitude, z);
+
+		double dx = pixelX - mBBoxCoords[0] / mScale;
+		double dy = pixelY - mBBoxCoords[1] / mScale;
+		double lon = MercatorProjection.pixelXToLongitude(dx, z);
+		double lat = MercatorProjection.pixelYToLatitude(dy, z);
+		Log.d(">>>", "bl:" + lon + " " + lat);
+
+		dx = pixelX - mBBoxCoords[2] / mScale;
+		dy = pixelY - mBBoxCoords[3] / mScale;
+		lon = MercatorProjection.pixelXToLongitude(dx, z);
+		lat = MercatorProjection.pixelYToLatitude(dy, z);
+		Log.d("...", "br:" + lon + " " + lat);
+
+		dx = pixelX - mBBoxCoords[4] / mScale;
+		dy = pixelY - mBBoxCoords[5] / mScale;
+		lon = MercatorProjection.pixelXToLongitude(dx, z);
+		lat = MercatorProjection.pixelYToLatitude(dy, z);
+		Log.d("...", "tl:" + lon + " " + lat);
+
+		dx = pixelX - mBBoxCoords[6] / mScale;
+		dy = pixelY - mBBoxCoords[7] / mScale;
+		lon = MercatorProjection.pixelXToLongitude(dx, z);
+		lat = MercatorProjection.pixelYToLatitude(dy, z);
+		Log.d("...", "tr:" + lon + " " + lat);
+
+	}
 
 	/**
 	 * @return the current center point of the MapView.
@@ -168,6 +306,15 @@ public class MapViewPosition {
 		return new GeoPoint(latitude, longitude);
 	}
 
+	// public static double pixelXToLongitude(double pixelX, byte zoomLevel) {
+	// return 360 * ((pixelX / ((long) Tile.TILE_SIZE << zoomLevel)) - 0.5);
+	// }
+	//
+	// public static double pixelYToLatitude(double pixelY, byte zoomLevel) {
+	// double y = 0.5 - (pixelY / ((long) Tile.TILE_SIZE << zoomLevel));
+	// return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI;
+	// }
+
 	/**
 	 * Moves this MapViewPosition by the given amount of pixels.
 	 * 
@@ -187,14 +334,13 @@ public class MapViewPosition {
 			double rad = Math.toRadians(mRotation);
 			double x = dx * Math.cos(rad) + dy * -Math.sin(rad);
 			double y = dx * Math.sin(rad) + dy * Math.cos(rad);
+			dx = x;
+			dy = y;
+		}
+
+		dx = pixelX - dx;
+		dy = pixelY - dy;
 
-			dx = pixelX - x;
-			dy = pixelY - y;
-		}
-		else {
-			dx = pixelX - dx;
-			dy = pixelY - dy;
-		}
 		mLatitude = MercatorProjection.pixelYToLatitude(dy, mZoomLevel);
 		mLatitude = MercatorProjection.limitLatitude(mLatitude);
 
@@ -202,6 +348,8 @@ public class MapViewPosition {
 
 		mLongitude = MercatorProjection.wrapLongitude(mLongitude);
 		// mLongitude = MercatorProjection.limitLongitude(mLongitude);
+
+		// getViewBox(null);
 	}
 
 	public synchronized void rotateMap(float angle, float cx, float cy) {
@@ -209,14 +357,17 @@ public class MapViewPosition {
 		// Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation -
 		// angle));
 		mRotation -= angle;
+		updateMatrix();
 	}
 
 	public void setRotation(float f) {
 		mRotation = f;
+		updateMatrix();
 	}
 
 	public void setTilt(float f) {
 		mTilt = f;
+		updateMatrix();
 	}
 
 	synchronized void setMapCenter(GeoPoint geoPoint) {
@@ -251,38 +402,41 @@ public class MapViewPosition {
 	 *            ...
 	 * @param pivotY
 	 *            ...
+	 * @return true if scale was changed
 	 */
-	public synchronized void scaleMap(float scale, float pivotX, float pivotY) {
-		if (pivotY != 0 || pivotY != 0)
-			moveMap(pivotX * (1.0f - scale),
-					pivotY * (1.0f - scale));
+	public synchronized boolean scaleMap(float scale, float pivotX, float pivotY) {
 
 		float newScale = mMapScale * scale;
 
 		int z = FastMath.log2((int) newScale);
 
 		if (z <= 0 || (z >= MAX_ZOOMLEVEL && mScale >= 8))
-			return;
+			return false;
 
 		if (z > MAX_ZOOMLEVEL) {
 			// z16 shows everything, just increase scaling
 			if (mScale * scale > 8)
-				return;
+				return false;
 
 			mScale *= scale;
 			mMapScale = newScale;
-			return;
+		} else {
+			mZoomLevel = (byte) z;
+			mScale = newScale / (1 << z);
+			mMapScale = newScale;
 		}
 
-		mZoomLevel = (byte) z;
-		mScale = newScale / (1 << z);
-		mMapScale = newScale;
+		if (pivotY != 0 || pivotY != 0)
+			moveMap(pivotX * (1.0f - scale),
+					pivotY * (1.0f - scale));
+
+		return true;
 	}
 
 	public boolean tilt(float moveX) {
 		float tilt = mTilt + moveX;
-		if (tilt > 25)
-			tilt = 25;
+		if (tilt > MAX_ANGLE)
+			tilt = MAX_ANGLE;
 		else if (tilt < 0)
 			tilt = 0;
 		if (mTilt == tilt)
diff --git a/src/org/oscim/view/MapZoomControls.java b/src/org/oscim/view/MapZoomControls.java
index b4d056ff..9fcee335 100644
--- a/src/org/oscim/view/MapZoomControls.java
+++ b/src/org/oscim/view/MapZoomControls.java
@@ -123,8 +123,8 @@ public class MapZoomControls {
 		mShowMapZoomControls = true;
 		mZoomLevelMax = DEFAULT_ZOOM_LEVEL_MAX;
 		mZoomLevelMin = DEFAULT_ZOOM_LEVEL_MIN;
-		if (!MapView.testRegionZoom)
-			mZoomControls.setVisibility(View.GONE);
+		// if (!MapView.testRegionZoom)
+		mZoomControls.setVisibility(View.GONE);
 		mZoomControlsGravity = DEFAULT_ZOOM_CONTROLS_GRAVITY;
 
 		mZoomControls.setOnZoomInClickListener(new ZoomInClickListener(this));
@@ -203,12 +203,14 @@ public class MapZoomControls {
 	}
 
 	/**
-	 * Sets the gravity for the placing of the zoom controls. Supported values are {@link Gravity#TOP},
-	 * {@link Gravity#CENTER_VERTICAL}, {@link Gravity#BOTTOM}, {@link Gravity#LEFT}, {@link Gravity#CENTER_HORIZONTAL}
-	 * and {@link Gravity#RIGHT}.
+	 * Sets the gravity for the placing of the zoom controls. Supported values
+	 * are {@link Gravity#TOP}, {@link Gravity#CENTER_VERTICAL},
+	 * {@link Gravity#BOTTOM}, {@link Gravity#LEFT},
+	 * {@link Gravity#CENTER_HORIZONTAL} and {@link Gravity#RIGHT}.
 	 * 
 	 * @param zoomControlsGravity
-	 *            a combination of {@link Gravity} constants describing the desired placement.
+	 *            a combination of {@link Gravity} constants describing the
+	 *            desired placement.
 	 */
 	public void setZoomControlsGravity(int zoomControlsGravity) {
 		if (mZoomControlsGravity != zoomControlsGravity) {
@@ -220,14 +222,16 @@ public class MapZoomControls {
 	/**
 	 * Sets the maximum zoom level of the map.
 	 * <p>
-	 * The maximum possible zoom level of the MapView depends also on the current {@link TileGenerator}. For example,
-	 * downloading map tiles may only be possible up to a certain zoom level. Setting a higher maximum zoom level has no
-	 * effect in this case.
+	 * The maximum possible zoom level of the MapView depends also on the
+	 * current {@link TileGenerator}. For example, downloading map tiles may
+	 * only be possible up to a certain zoom level. Setting a higher maximum
+	 * zoom level has no effect in this case.
 	 * 
 	 * @param zoomLevelMax
 	 *            the maximum zoom level.
 	 * @throws IllegalArgumentException
-	 *             if the maximum zoom level is smaller than the current minimum zoom level.
+	 *             if the maximum zoom level is smaller than the current minimum
+	 *             zoom level.
 	 */
 	public void setZoomLevelMax(byte zoomLevelMax) {
 		if (zoomLevelMax < mZoomLevelMin) {
@@ -242,7 +246,8 @@ public class MapZoomControls {
 	 * @param zoomLevelMin
 	 *            the minimum zoom level.
 	 * @throws IllegalArgumentException
-	 *             if the minimum zoom level is larger than the current maximum zoom level.
+	 *             if the minimum zoom level is larger than the current maximum
+	 *             zoom level.
 	 */
 	public void setZoomLevelMin(byte zoomLevelMin) {
 		if (zoomLevelMin > mZoomLevelMax) {
diff --git a/src/org/oscim/view/RegionLookup.java b/src/org/oscim/view/RegionLookup.java
index 64a94283..ad2f84eb 100644
--- a/src/org/oscim/view/RegionLookup.java
+++ b/src/org/oscim/view/RegionLookup.java
@@ -23,7 +23,6 @@ import java.util.ArrayList;
 import java.util.Properties;
 
 import org.oscim.core.GeoPoint;
-import org.oscim.core.MapPosition;
 import org.oscim.core.MercatorProjection;
 
 import android.os.AsyncTask;
diff --git a/src/org/oscim/view/TouchHandler.java b/src/org/oscim/view/TouchHandler.java
index 275e9867..9cac217b 100644
--- a/src/org/oscim/view/TouchHandler.java
+++ b/src/org/oscim/view/TouchHandler.java
@@ -32,20 +32,24 @@ import android.widget.Scroller;
  * Implementation for multi-touch capable devices. TODO write a AnimationTimer
  * instead of using CountDownTimer
  */
-public class TouchHandler {
+public class TouchHandler
+		extends SimpleOnGestureListener
+		implements ScaleGestureDetector.OnScaleGestureListener {
+
+	private static final float SCALE_DURATION = 450;
 	private static final int INVALID_POINTER_ID = -1;
 
-	/* package */final MapView mMapView;
-	/* package */final MapViewPosition mMapPosition;
-	/* package */final DecelerateInterpolator mInterpolator = new DecelerateInterpolator();
-	/* package */boolean mBeginScale;
-	/* package */float mSumScale;
+	private final MapView mMapView;
+	private final MapViewPosition mMapPosition;
+	private final DecelerateInterpolator mInterpolator = new DecelerateInterpolator();
+	private boolean mBeginScale;
+	private float mSumScale;
 
 	private final float mMapMoveDelta;
 	private boolean mMoveStart;
 	private boolean mBeginRotate;
-	/* package */float mPosX;
-	/* package */float mPosY;
+	private float mPosX;
+	private float mPosY;
 	private double mAngle;
 
 	private int mActivePointerId;
@@ -65,9 +69,47 @@ public class TouchHandler {
 		mMapPosition = mapView.getMapPosition();
 		mMapMoveDelta = viewConfiguration.getScaledTouchSlop();
 		mActivePointerId = INVALID_POINTER_ID;
-		mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleListener());
-		mGestureDetector = new GestureDetector(context, new MapGestureDetector());
+		mScaleGestureDetector = new ScaleGestureDetector(context, this);
+		mGestureDetector = new GestureDetector(context, this);
 
+		mScroller = new Scroller(mMapView.getContext(),
+				new android.view.animation.LinearInterpolator());
+	}
+
+	/**
+	 * @param event
+	 *            ...
+	 * @return ...
+	 */
+	public boolean handleMotionEvent(MotionEvent event) {
+
+		// workaround for a bug in the ScaleGestureDetector, see Android issue
+		// #12976
+		// if (event.getAction() != MotionEvent.ACTION_MOVE
+		// || event.getPointerCount() > 1) {
+		mScaleGestureDetector.onTouchEvent(event);
+		// }
+
+		if (!mScaling)
+			mGestureDetector.onTouchEvent(event);
+
+		int action = getAction(event);
+		boolean ret = false;
+		if (action == MotionEvent.ACTION_DOWN) {
+			ret = onActionDown(event);
+		} else if (action == MotionEvent.ACTION_MOVE) {
+			ret = onActionMove(event);
+		} else if (action == MotionEvent.ACTION_UP) {
+			ret = onActionUp(event);
+		} else if (action == MotionEvent.ACTION_CANCEL) {
+			ret = onActionCancel();
+		} else if (action == MotionEvent.ACTION_POINTER_DOWN) {
+			return onActionPointerDown(event);
+		} else if (action == MotionEvent.ACTION_POINTER_UP) {
+			ret = onActionPointerUp(event);
+		}
+
+		return ret;
 	}
 
 	private static int getAction(MotionEvent motionEvent) {
@@ -131,48 +173,46 @@ public class TouchHandler {
 			return true;
 		}
 
-		if (mMapView.enableRotation) {
-			if (multi > 0) {
-				double x1 = event.getX(0);
-				double x2 = event.getX(1);
-				double y1 = event.getY(0);
-				double y2 = event.getY(1);
+		if (!mMapView.enableRotation || multi < 1)
+			return true;
 
-				double dx = x1 - x2;
-				double dy = y1 - y2;
+		double x1 = event.getX(0);
+		double x2 = event.getX(1);
+		double y1 = event.getY(0);
+		double y2 = event.getY(1);
 
-				double rad = Math.atan2(dy, dx);
-				double r = rad - mAngle;
+		double dx = x1 - x2;
+		double dy = y1 - y2;
 
-				if (!mBeginRotate && Math.abs(dy) < 80) {
-					if (mMapPosition.tilt(moveY / 4)) {
-						mMapView.redrawMap();
-						return true;
-					}
-				}
-
-				if (!mBeginRotate && !mBeginScale) {
-					if (r > 0.02 || r < -0.02)
-						mBeginRotate = true;
-				} else if (mBeginRotate) {
-					double rsin = Math.sin(r);
-					double rcos = Math.cos(r);
-
-					// focus point relative to center
-					double cx = (mMapView.getWidth() >> 1) - (x1 + x2) / 2;
-					double cy = (mMapView.getHeight() >> 1) - (y1 + y2) / 2;
-
-					float x = (float) (cx * rcos + cy * -rsin - cx);
-					float y = (float) (cx * rsin + cy * rcos - cy);
-
-					mMapPosition.rotateMap((float) Math.toDegrees(rad - mAngle), x, y);
-					mAngle = rad;
-					mMapView.redrawMap();
-				}
+		double rad = Math.atan2(dy, dx);
+		double r = rad - mAngle;
 
+		if (!mBeginRotate && Math.abs(dy) < 80) {
+			if (mMapPosition.tilt(moveY / 4)) {
+				mMapView.redrawMap();
+				return true;
 			}
 		}
 
+		if (!mBeginRotate && !mBeginScale) {
+			if (r > 0.02 || r < -0.02)
+				mBeginRotate = true;
+		} else if (mBeginRotate) {
+			double rsin = Math.sin(r);
+			double rcos = Math.cos(r);
+
+			// focus point relative to center
+			double cx = (mMapView.getWidth() >> 1) - (x1 + x2) / 2;
+			double cy = (mMapView.getHeight() >> 1) - (y1 + y2) / 2;
+
+			float x = (float) (cx * rcos + cy * -rsin - cx);
+			float y = (float) (cx * rsin + cy * rcos - cy);
+
+			mMapPosition.rotateMap((float) Math.toDegrees(rad - mAngle), x, y);
+			mAngle = rad;
+			mMapView.redrawMap();
+		}
+
 		return true;
 	}
 
@@ -225,285 +265,240 @@ public class TouchHandler {
 		return true;
 	}
 
-	/**
-	 * @param event
-	 *            ...
-	 * @return ...
-	 */
-	public boolean handleMotionEvent(MotionEvent event) {
+	/******************* SimpleOnGestureListener *******************/
 
-		// workaround for a bug in the ScaleGestureDetector, see Android issue
-		// #12976
-		// if (event.getAction() != MotionEvent.ACTION_MOVE
-		// || event.getPointerCount() > 1) {
-		mScaleGestureDetector.onTouchEvent(event);
-		// }
+	private Scroller mScroller;
+	private float mScrollX, mScrollY;
+	private boolean fling = false;
 
-		if (!mScaling)
-			mGestureDetector.onTouchEvent(event);
-
-		int action = getAction(event);
-		boolean ret = false;
-		if (action == MotionEvent.ACTION_DOWN) {
-			ret = onActionDown(event);
-		} else if (action == MotionEvent.ACTION_MOVE) {
-			ret = onActionMove(event);
-		} else if (action == MotionEvent.ACTION_UP) {
-			ret = onActionUp(event);
-		} else if (action == MotionEvent.ACTION_CANCEL) {
-			ret = onActionCancel();
-		} else if (action == MotionEvent.ACTION_POINTER_DOWN) {
-			return onActionPointerDown(event);
-		} else if (action == MotionEvent.ACTION_POINTER_UP) {
-			ret = onActionPointerUp(event);
-		}
-
-		return ret;
-	}
-
-	class MapGestureDetector extends SimpleOnGestureListener {
-		private Scroller mScroller;
-		private float mScrollX, mScrollY, mPrevScale;
-		private CountDownTimer mTimer = null;
-		private boolean fling = false;
-
-		public MapGestureDetector() {
-			mScroller = new Scroller(mMapView.getContext(),
-					new android.view.animation.LinearInterpolator());
-		}
-
-		@Override
-		public boolean onDown(MotionEvent e) {
-			if (fling) {
-				mScroller.forceFinished(true);
-
-				if (mTimer != null) {
-					mTimer.cancel();
-					mTimer = null;
-				}
-				fling = false;
-			}
-			// Log.d("mapsforge", "onDown");
-
-			return true;
-		}
-
-		boolean scroll() {
-			if (mScroller.isFinished()) {
-				return false;
-			}
-			mScroller.computeScrollOffset();
-
-			float moveX = mScroller.getCurrX() - mScrollX;
-			float moveY = mScroller.getCurrY() - mScrollY;
-
-			if (moveX >= 1 || moveY >= 1 || moveX <= -1 || moveY <= -1) {
-				mMapPosition.moveMap(moveX, moveY);
-				mMapView.redrawMap();
-				mScrollX = mScroller.getCurrX();
-				mScrollY = mScroller.getCurrY();
-			}
-			return true;
-		}
-
-		@Override
-		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
-				float velocityY) {
-			int w = Tile.TILE_SIZE * 20;
-			int h = Tile.TILE_SIZE * 20;
-			mScrollX = 0;
-			mScrollY = 0;
+	@Override
+	public boolean onDown(MotionEvent e) {
+		if (fling) {
+			mScroller.forceFinished(true);
 
 			if (mTimer != null) {
 				mTimer.cancel();
 				mTimer = null;
 			}
+			fling = false;
+		}
+		// Log.d("mapsforge", "onDown");
 
-			mScroller.fling(0, 0, Math.round(velocityX) / 2, Math.round(velocityY) / 2,
-					-w, w, -h, h);
+		return true;
+	}
 
-			// animate for two seconds
-			mTimer = new CountDownTimer(1500, 50) {
+	boolean scroll() {
+		if (mScroller.isFinished()) {
+			return false;
+		}
+		mScroller.computeScrollOffset();
+
+		float moveX = mScroller.getCurrX() - mScrollX;
+		float moveY = mScroller.getCurrY() - mScrollY;
+
+		if (moveX >= 1 || moveY >= 1 || moveX <= -1 || moveY <= -1) {
+			mMapPosition.moveMap(moveX, moveY);
+			mMapView.redrawMap();
+			mScrollX = mScroller.getCurrX();
+			mScrollY = mScroller.getCurrY();
+		}
+		return true;
+	}
+
+	@Override
+	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+			float velocityY) {
+		int w = Tile.TILE_SIZE * 20;
+		int h = Tile.TILE_SIZE * 20;
+		mScrollX = 0;
+		mScrollY = 0;
+
+		if (mTimer != null) {
+			mTimer.cancel();
+			mTimer = null;
+		}
+
+		mScroller.fling(0, 0, Math.round(velocityX) / 2, Math.round(velocityY) / 2,
+				-w, w, -h, h);
+
+		// animate for two seconds
+		mTimer = new CountDownTimer(1500, 50) {
+			@Override
+			public void onTick(long tick) {
+				scroll();
+			}
+
+			@Override
+			public void onFinish() {
+				// do nothing
+			}
+		}.start();
+		fling = true;
+		return true;
+	}
+
+	@Override
+	public void onLongPress(MotionEvent e) {
+		if (MapView.testRegionZoom) {
+			Log.d("mapsforge", "long press");
+			mMapView.mRegionLookup.updateRegion(-1, null);
+		}
+	}
+
+	boolean scale2(long tick) {
+
+		fling = true;
+		if (mPrevScale >= 1)
+			return false;
+		float adv = (SCALE_DURATION - tick) / SCALE_DURATION;
+		adv = mInterpolator.getInterpolation(adv);
+
+		float scale = adv - mPrevScale;
+		mPrevScale += scale;
+		scale += 1;
+		adv += 1;
+
+		if (scale > 1) {
+			mMapPosition.scaleMap(scale, mScrollX / adv, mScrollY / adv);
+			mMapView.redrawMap();
+		}
+
+		return true;
+	}
+
+	@Override
+	public boolean onDoubleTap(MotionEvent e) {
+		if (MapView.testRegionZoom) {
+			Log.d("mapsforge", "double tap");
+
+			mMapView.mRegionLookup.updateRegion(1,
+					mMapPosition.getOffsetPoint(mPosX, mPosY));
+		} else {
+			mScrollX = (e.getX(0) - (mMapView.getWidth() >> 1)) * 2f;
+			mScrollY = (e.getY(0) - (mMapView.getHeight() >> 1)) * 2f;
+			mPrevScale = 0;
+
+			mTimer = new CountDownTimer((int) SCALE_DURATION, 30) {
 				@Override
 				public void onTick(long tick) {
-					scroll();
+					scale2(tick);
 				}
 
 				@Override
 				public void onFinish() {
-					// do nothing
+					scale(0);
 				}
 			}.start();
-			fling = true;
-			return true;
-		}
-
-		@Override
-		public void onLongPress(MotionEvent e) {
-			if (MapView.testRegionZoom) {
-				Log.d("mapsforge", "long press");
-				mMapView.mRegionLookup.updateRegion(-1, null);
-			}
-		}
-
-		private final float mScaleDuration = 300;
-
-		boolean scale(long tick) {
-
-			fling = true;
-			if (mPrevScale >= 1)
-				return false;
-			float adv = (mScaleDuration - tick) / mScaleDuration;
-			adv = mInterpolator.getInterpolation(adv);
-
-			float scale = adv - mPrevScale;
-			mPrevScale += scale;
-			scale += 1;
-			adv += 1;
-
-			if (scale > 1) {
-				mMapPosition.scaleMap(scale, mScrollX / adv, mScrollY / adv);
-				mMapView.redrawMap();
-			}
-
-			return true;
-		}
-
-		@Override
-		public boolean onDoubleTap(MotionEvent e) {
-			if (MapView.testRegionZoom) {
-				Log.d("mapsforge", "double tap");
-
-				mMapView.mRegionLookup.updateRegion(1,
-						mMapPosition.getOffsetPoint(mPosX, mPosY));
-			} else {
-				mScrollX = (e.getX(0) - (mMapView.getWidth() >> 1)) * 2f;
-				mScrollY = (e.getY(0) - (mMapView.getHeight() >> 1)) * 2f;
-				mPrevScale = 0;
-
-				mTimer = new CountDownTimer((int) mScaleDuration, 30) {
-					@Override
-					public void onTick(long tick) {
-						scale(tick);
-					}
-
-					@Override
-					public void onFinish() {
-						scale(0);
-					}
-				}.start();
-			}
-			return true;
 		}
+		return true;
 	}
 
-	class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener {
-		private float mCenterX;
-		private float mCenterY;
-		private float mFocusX;
-		private float mFocusY;
-		private long mTimeStart;
-		private long mTimeEnd;
+	/******************* ScaleListener *******************/
 
-		@Override
-		public boolean onScale(ScaleGestureDetector gd) {
+	private float mCenterX;
+	private float mCenterY;
+	private float mFocusX;
+	private float mFocusY;
+	private long mTimeStart;
+	private long mTimeEnd;
 
-			float scale = gd.getScaleFactor();
-			mFocusX = gd.getFocusX() - mCenterX;
-			mFocusY = gd.getFocusY() - mCenterY;
+	@Override
+	public boolean onScale(ScaleGestureDetector gd) {
 
-			mSumScale *= scale;
+		float scale = gd.getScaleFactor();
+		mFocusX = gd.getFocusX() - mCenterX;
+		mFocusY = gd.getFocusY() - mCenterY;
 
-			mTimeEnd = SystemClock.elapsedRealtime();
+		mSumScale *= scale;
 
-			if (!mBeginScale) {
-				if (mTimeEnd - mTimeStart > 150 || mSumScale > 1.1 || mSumScale < 0.9) {
-					mBeginScale = true;
-					scale = mSumScale;
+		mTimeEnd = SystemClock.elapsedRealtime();
+
+		if (!mBeginScale) {
+			if (mTimeEnd - mTimeStart > 150 || mSumScale > 1.1 || mSumScale < 0.9) {
+				mBeginScale = true;
+				scale = mSumScale;
+			}
+			else
+				return true;
+		}
+
+		if (mMapPosition.scaleMap(scale, mFocusX, mFocusY))
+			mMapView.redrawMap();
+
+		return true;
+	}
+
+	@Override
+	public boolean onScaleBegin(ScaleGestureDetector gd) {
+		mTimeEnd = mTimeStart = SystemClock.elapsedRealtime();
+		mSumScale = 1;
+		mBeginScale = false;
+		mCenterX = mMapView.getWidth() >> 1;
+		mCenterY = mMapView.getHeight() >> 1;
+
+		if (mTimer != null) {
+			mTimer.cancel();
+			mTimer = null;
+		}
+		return true;
+	}
+
+	@Override
+	public void onScaleEnd(ScaleGestureDetector gd) {
+		// Log.d("ScaleListener", "Sum " + mSumScale + " " + (mTimeEnd -
+		// mTimeStart));
+
+		if (mTimer == null && mTimeEnd - mTimeStart < 150
+				&& (mSumScale < 0.99 || mSumScale > 1.01)) {
+
+			mPrevScale = 0;
+
+			mZooutOut = mSumScale < 0.99;
+
+			mTimer = new CountDownTimer((int) SCALE_DURATION, 15) {
+				@Override
+				public void onTick(long tick) {
+					scale(tick);
 				}
-				else
-					return true;
-			}
 
-			mMapPosition.scaleMap(scale, mFocusX, mFocusY);
-			mMapView.redrawMap();
+				@Override
+				public void onFinish() {
+					scale(0);
 
-			return true;
+				}
+			}.start();
+		}
+		mBeginScale = false;
+	}
+
+	private float mPrevScale;
+	private CountDownTimer mTimer;
+	boolean mZooutOut;
+
+	boolean scale(long tick) {
+
+		if (mPrevScale >= 1) {
+			mTimer = null;
+			return false;
 		}
 
-		@Override
-		public boolean onScaleBegin(ScaleGestureDetector gd) {
-			mTimeEnd = mTimeStart = SystemClock.elapsedRealtime();
-			mSumScale = 1;
-			mBeginScale = false;
-			mCenterX = mMapView.getWidth() >> 1;
-			mCenterY = mMapView.getHeight() >> 1;
+		float adv = (SCALE_DURATION - tick) / SCALE_DURATION;
+		adv = mInterpolator.getInterpolation(adv);
 
-			if (mTimer != null) {
-				mTimer.cancel();
-				mTimer = null;
-			}
-			return true;
+		float scale = adv - mPrevScale;
+		mPrevScale += scale;
+
+		if (mZooutOut) {
+			mMapPosition.scaleMap(1 - scale, 0, 0);
+		} else {
+			mMapPosition.scaleMap(1 + scale, mFocusX, mFocusY);
 		}
 
-		@Override
-		public void onScaleEnd(ScaleGestureDetector gd) {
-			// Log.d("ScaleListener", "Sum " + mSumScale + " " + (mTimeEnd -
-			// mTimeStart));
+		mMapView.redrawMap();
 
-			if (mTimer == null && mTimeEnd - mTimeStart < 150
-					&& (mSumScale < 0.99 || mSumScale > 1.01)) {
+		if (tick == 0)
+			mTimer = null;
 
-				mPrevScale = 0;
-
-				mZooutOut = mSumScale < 0.99;
-
-				mTimer = new CountDownTimer((int) mScaleDuration, 15) {
-					@Override
-					public void onTick(long tick) {
-						scale(tick);
-					}
-
-					@Override
-					public void onFinish() {
-						scale(0);
-
-					}
-				}.start();
-			}
-			mBeginScale = false;
-		}
-
-		private float mPrevScale;
-		private CountDownTimer mTimer;
-		boolean mZooutOut;
-		private final float mScaleDuration = 450;
-
-		boolean scale(long tick) {
-
-			if (mPrevScale >= 1) {
-				mTimer = null;
-				return false;
-			}
-
-			float adv = (mScaleDuration - tick) / mScaleDuration;
-			adv = mInterpolator.getInterpolation(adv);
-
-			float scale = adv - mPrevScale;
-			mPrevScale += scale;
-
-			if (mZooutOut) {
-				mMapPosition.scaleMap(1 - scale, 0, 0);
-			} else {
-				mMapPosition.scaleMap(1 + scale, mFocusX, mFocusY);
-			}
-
-			mMapView.redrawMap();
-
-			if (tick == 0)
-				mTimer = null;
-
-			return true;
-		}
+		return true;
 	}
 }
diff --git a/src/org/oscim/view/generator/MapWorker.java b/src/org/oscim/view/generator/MapWorker.java
index 1fdbb1d3..d54f2cae 100644
--- a/src/org/oscim/view/generator/MapWorker.java
+++ b/src/org/oscim/view/generator/MapWorker.java
@@ -15,12 +15,12 @@
 package org.oscim.view.generator;
 
 import org.oscim.utils.PausableThread;
-import org.oscim.view.renderer.TileGenerator;
 import org.oscim.view.renderer.MapRenderer;
+import org.oscim.view.renderer.TileGenerator;
 
 /**
- * A MapWorker uses a {@link IMapGenerator} to generate map tiles. It runs in a separate thread to avoid blocking the UI
- * thread.
+ * A MapWorker uses a {@link TileGenerator} to generate map tiles. It runs in a
+ * separate thread to avoid blocking the UI thread.
  */
 public class MapWorker extends PausableThread {
 	private final String THREAD_NAME;
@@ -28,11 +28,11 @@ public class MapWorker extends PausableThread {
 	private final TileGenerator mMapGenerator;
 	private final MapRenderer mMapRenderer;
 
-	// private final int mPrio;
-
 	/**
 	 * @param id
 	 *            thread id
+	 * @param jobQueue
+	 *            ...
 	 * @param tileGenerator
 	 *            ...
 	 * @param mapRenderer
@@ -46,7 +46,6 @@ public class MapWorker extends PausableThread {
 		mMapRenderer = mapRenderer;
 
 		THREAD_NAME = "MapWorker" + id;
-		// mPrio = Math.max(Thread.MIN_PRIORITY + id, Thread.NORM_PRIORITY - 1);
 	}
 
 	public TileGenerator getMapGenerator() {
@@ -85,7 +84,6 @@ public class MapWorker extends PausableThread {
 	@Override
 	protected int getThreadPriority() {
 		return (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 3;
-		// return mPrio;
 	}
 
 	@Override
diff --git a/src/org/oscim/view/renderer/GLRenderer.java b/src/org/oscim/view/renderer/GLRenderer.java
index 5f6dea6d..f0888691 100644
--- a/src/org/oscim/view/renderer/GLRenderer.java
+++ b/src/org/oscim/view/renderer/GLRenderer.java
@@ -32,11 +32,13 @@ import java.util.concurrent.locks.ReentrantLock;
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
 
-import org.oscim.core.MapPosition;
 import org.oscim.core.Tile;
 import org.oscim.theme.RenderTheme;
 import org.oscim.utils.GlUtils;
+import org.oscim.view.MapPosition;
 import org.oscim.view.MapView;
+import org.oscim.view.MapViewPosition;
+import org.oscim.view.renderer.MapRenderer.TilesData;
 
 import android.opengl.GLES20;
 import android.opengl.GLSurfaceView;
@@ -59,6 +61,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 	static int CACHE_TILES = CACHE_TILES_MAX;
 
 	private final MapView mMapView;
+	private final MapViewPosition mMapViewPosition;
+
+	private static final MapPosition mMapPosition = new MapPosition();
+
 	private static ArrayList<VertexBufferObject> mVBOs;
 
 	private static int mWidth, mHeight;
@@ -71,12 +77,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 	private static int mBufferMemoryUsage;
 
 	private static float[] mMVPMatrix = new float[16];
-	private static float[] mRotateMatrix = new float[16];
-	private static float[] mTmpMatrix = new float[16];
-	private static float[] mTmp2Matrix = new float[16];
-
 	private static float[] mProjMatrix = new float[16];
-	private static float[] mProjMatrixI = new float[16];
+	private static float[] mTileCoords = new float[8];
 
 	// mNextTiles is set by TileLoader and swapped with
 	// mDrawTiles in onDrawFrame in GL thread.
@@ -86,8 +88,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 	// changed. used in onDrawFrame to flip mNextTiles/mDrawTiles
 	private static boolean mUpdateTiles;
 
-	private static MapPosition mCurPosition;
-
 	private float[] mClearColor = null;
 
 	// number of tiles drawn in one frame
@@ -98,17 +98,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 	// lock to synchronize Main- and GL-Thread
 	static ReentrantLock tilelock = new ReentrantLock();
 
-	// used for passing tiles to be rendered from TileLoader(Main-Thread) to
-	// GLThread
-	static class TilesData {
-		int cnt = 0;
-		final MapTile[] tiles;
-
-		TilesData(int numTiles) {
-			tiles = new MapTile[numTiles];
-		}
-	}
-
 	/**
 	 * @param mapView
 	 *            the MapView
@@ -117,34 +106,27 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		Log.d(TAG, "init MapRenderer");
 
 		mMapView = mapView;
+		mMapViewPosition = mapView.getMapViewPosition();
+		// mMapPosition = new MapPosition();
+
+		mMapPosition.init();
+
 		Matrix.setIdentityM(mMVPMatrix, 0);
 
 		mUpdateTiles = false;
 	}
 
-	/**
-	 * called by TileLoader when only position changed
-	 * 
-	 * @param mapPosition
-	 *            current MapPosition
-	 */
-	static void updatePosition(MapPosition mapPosition) {
-		mCurPosition = mapPosition;
-	}
-
 	/**
 	 * called by TileLoader when list of active tiles changed
 	 * 
-	 * @param mapPosition
-	 *            current MapPosition
 	 * @param tiles
 	 *            active tiles
 	 * @return mNextTiles (the previously active tiles)
 	 */
-	static TilesData updateTiles(MapPosition mapPosition, TilesData tiles) {
+	static TilesData updateTiles(TilesData tiles) {
 		GLRenderer.tilelock.lock();
 
-		mCurPosition = mapPosition;
+		// mCurPosition = mapPosition;
 
 		// unlock previously active tiles
 		for (int i = 0; i < mNextTiles.cnt; i++) {
@@ -178,13 +160,13 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		// lock tiles (and their proxies) to not be removed from cache
 		for (int i = 0; i < mNextTiles.cnt; i++) {
 			MapTile t = mNextTiles.tiles[i];
-			if (!t.isActive)
+			if (!t.isLocked)
 				t.lock();
 		}
 
 		for (int j = 0; j < mDrawTiles.cnt; j++) {
 			MapTile t = mDrawTiles.tiles[j];
-			if (!t.isActive)
+			if (!t.isLocked)
 				t.lock();
 		}
 
@@ -386,8 +368,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 			CACHE_TILES -= 50;
 	}
 
-	private static boolean isVisible(MapPosition mapPosition, MapTile tile) {
+	private static boolean isVisible(MapTile tile) {
 		float dx, dy, scale, div = 1;
+		MapPosition mapPosition = mMapPosition;
 		int diff = mapPosition.zoomLevel - tile.zoomLevel;
 
 		if (diff < 0)
@@ -407,7 +390,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		// this kindof works for typical screen aspect
 		if (mRotate) {
 			int ssize = mWidth > mHeight ? mWidth : mHeight;
-
+			ssize += Tile.TILE_SIZE;
 			if (sy > ssize / 2 || sx > ssize / 2
 					|| sx + size * scale < -ssize / 2
 					|| sy + size * scale < -ssize / 2) {
@@ -429,10 +412,12 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 
 	private static boolean mRotate = false;
 
-	private static void setMatrix(float[] matrix, MapPosition mapPosition, MapTile tile,
+	private static void setMatrix(float[] matrix, MapTile tile,
 			float div, boolean project) {
 		float x, y, scale;
 
+		MapPosition mapPosition = mMapPosition;
+
 		scale = mapPosition.scale / (div * COORD_MULTIPLIER);
 		x = (float) (tile.pixelX - mapPosition.x * div);
 		y = (float) (tile.pixelY - mapPosition.y * div);
@@ -443,48 +428,30 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		Matrix.scaleM(matrix, 0, scale, scale, 1);
 
 		// translate relative to map center
-		Matrix.translateM(matrix, 0,
-				x * COORD_MULTIPLIER,
-				-(y + Tile.TILE_SIZE) * COORD_MULTIPLIER,
-				-1); // put on near plane
+		Matrix.translateM(matrix, 0, x * COORD_MULTIPLIER,
+				-(y + Tile.TILE_SIZE) * COORD_MULTIPLIER, 0);
 
 		if (mRotate)
-			Matrix.multiplyMM(matrix, 0, mRotateMatrix, 0, matrix, 0);
+			Matrix.multiplyMM(matrix, 0, mapPosition.rotation, 0, matrix, 0);
 
 		if (project)
 			Matrix.multiplyMM(matrix, 0, mProjMatrix, 0, matrix, 0);
 	}
 
-	// private float[] mv = new float[4];
-	// private float[] mu = { 1, 1, -1, 1 };
-	//
-	// private float[] mUnprojMatrix = new float[16];
-	//
-	// private void unproject(MapPosition pos, float x, float y) {
-	// mu[0] = x;
-	// mu[1] = y;
-	// mu[2] = -1;
-	//
-	// // add tilt
-	// Matrix.multiplyMV(mv, 0, mTmpMatrix, 0, mu, 0);
-	// // Log.d(TAG, ">> " + mv[0] + " " + mv[1] + " " + mv[2]);
-	//
-	// Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0);
-	// float size = Tile.TILE_SIZE * pos.scale;
-	// if (mv[3] != 0) {
-	// float w = 1 / mv[3];
-	// float xx = Math.round(((mv[0] * w) / size) * 100) / 100f;
-	// float yy = Math.round(((mv[1] * w) / size) * 100) / 100f;
-	// Log.d(TAG, " " + xx + " " + yy);
-	// }
-	// }
+	private static float scaleDiv(MapTile t) {
+		float div = 1;
+		int diff = mMapPosition.zoomLevel - t.zoomLevel;
+		if (diff < 0)
+			div = (1 << -diff);
+		else if (diff > 0)
+			div = (1.0f / (1 << diff));
+		return div;
+	}
 
 	@Override
 	public void onDrawFrame(GL10 glUnused) {
 		long start = 0;
 
-		MapPosition mapPosition;
-
 		if (MapView.debugFrameTime)
 			start = SystemClock.uptimeMillis();
 
@@ -498,66 +465,55 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 				| GLES20.GL_STENCIL_BUFFER_BIT);
 
 		// get position and current tiles to draw
-		GLRenderer.tilelock.lock();
-		mapPosition = mCurPosition;
+		// mapPosition = mCurPosition;
+
 		if (mUpdateTiles) {
+			GLRenderer.tilelock.lock();
 			TilesData tmp = mDrawTiles;
 			mDrawTiles = mNextTiles;
 			mNextTiles = tmp;
 			mUpdateTiles = false;
+			GLRenderer.tilelock.unlock();
 		}
-		GLRenderer.tilelock.unlock();
 
-		if (mDrawTiles == null)
+		if (mDrawTiles == null || mDrawTiles.cnt == 0)
 			return;
 
-		// if (mRotate != (mMapView.enableRotation || mMapView.enableCompass)) {
-		// Matrix.setIdentityM(mMVPMatrix, 0);
-		// mRotate = mMapView.enableRotation || mMapView.enableCompass;
-		// }
+		// MapPosition mapPosition =
+		// mMapView.getMapViewPosition().getMapPosition();
 
-		mRotate = mMapView.enableRotation || mMapView.enableCompass;
+		MapPosition mapPosition = mMapPosition;
+		boolean changed = mMapViewPosition.getMapPosition(mapPosition, mTileCoords);
 
-		if (mRotate) {
-			// rotate map
-			Matrix.setRotateM(mRotateMatrix, 0, mapPosition.angle, 0, 0, 1);
+		int tileCnt = mDrawTiles.cnt;
+		MapTile[] tiles = mDrawTiles.tiles;
 
-			// tilt map
-			// mMapView.getMapViewPosition().mTilt;
+		if (changed) {
+			for (int i = 0; i < tileCnt; i++)
+				tiles[i].isVisible = false;
 
-			float angle = mMapView.getMapViewPosition().mTilt / (mHeight / 2);
-			Matrix.setRotateM(mTmpMatrix, 0, -angle, 1, 0, 0);
+			// get relative zoom-level, tiles could not have been updated after
+			// zoom-level changed.
+			float div = scaleDiv(tiles[0]);
 
-			// move camera center back to map center
-			Matrix.translateM(mTmpMatrix, 0,
-					0, (float) Math.tan(Math.toRadians(angle)), 0);
+			mRotate = mMapView.enableRotation || mMapView.enableCompass;
 
-			// apply first rotation, then tilt
-			Matrix.multiplyMM(mRotateMatrix, 0, mTmpMatrix, 0, mRotateMatrix, 0);
+			float s = Tile.TILE_SIZE;
+			float scale = mapPosition.scale / div;
+			float px = (float) (mapPosition.x * div);
+			float py = (float) (mapPosition.y * div);
 
-			// // get unproject matrix
-			// Matrix.setIdentityM(mTmp2Matrix, 0);
-			// float s = mapPosition.scale;
-			// Matrix.translateM(mTmp2Matrix, 0,
-			// (float) (mapPosition.x * s),
-			// (float) (mapPosition.y * s), 0);
-			//
-			// Matrix.multiplyMM(mTmp2Matrix, 0, mRotateMatrix, 0, mTmp2Matrix,
-			// 0);
-			//
-			// // Matrix.invertM(mTmpMatrix, 0, mTmp2Matrix, 0);
-			// // (AB)^-1 = B^-1*A^-1
-			// Matrix.multiplyMM(mUnprojMatrix, 0, mTmp2Matrix, 0, mProjMatrixI,
-			// 0);
-			//
-			// // set tilt of screen coords
-			// Matrix.setRotateM(mTmpMatrix, 0, -15, 1, 0, 0);
-			//
-			// // unproject(mapPosition, 0, 0);
-			// unproject(mapPosition, -1, -1); // top-left
-			// unproject(mapPosition, 1, -1); // top-right
-			// unproject(mapPosition, -1, 1); // bottom-left
-			// unproject(mapPosition, 1, 1); // bottom-right
+			mTileCoords[0] = (px + mTileCoords[0] / scale) / s;
+			mTileCoords[1] = (py - mTileCoords[1] / scale) / s;
+			mTileCoords[2] = (px + mTileCoords[2] / scale) / s;
+			mTileCoords[3] = (py - mTileCoords[3] / scale) / s;
+			mTileCoords[4] = (px + mTileCoords[4] / scale) / s;
+			mTileCoords[5] = (py - mTileCoords[5] / scale) / s;
+			mTileCoords[6] = (px + mTileCoords[6] / scale) / s;
+			mTileCoords[7] = (py - mTileCoords[7] / scale) / s;
+
+			byte z = tiles[0].zoomLevel;
+			ScanBox.scan(mTileCoords, mDrawTiles, 1 << z);
 		}
 
 		if (mUpdateColor && mClearColor != null) {
@@ -566,9 +522,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 			mUpdateColor = false;
 		}
 
-		int tileCnt = mDrawTiles.cnt;
-		MapTile[] tiles = mDrawTiles.tiles;
-
 		uploadCnt = 0;
 		int updateTextures = 0;
 
@@ -576,7 +529,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		for (int i = 0; i < tileCnt; i++) {
 			MapTile tile = tiles[i];
 
-			if (!isVisible(mapPosition, tile))
+			// if (!isVisible(mapPosition, tile))
+			// continue;
+			if (!tile.isVisible)
 				continue;
 
 			if (tile.texture == null && TextRenderer.drawToTexture(tile))
@@ -616,14 +571,14 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 
 		for (int i = 0; i < tileCnt; i++) {
 			if (tiles[i].isVisible && tiles[i].isReady)
-				drawTile(mapPosition, tiles[i]);
+				drawTile(tiles[i]);
 		}
 
 		// proxies are clipped to the region where nothing was drawn to depth
 		// buffer. TODO draw all parent before grandparent
 		for (int i = 0; i < tileCnt; i++) {
 			if (tiles[i].isVisible && !tiles[i].isReady)
-				drawProxyTile(mapPosition, tiles[i]);
+				drawProxyTile(tiles[i]);
 		}
 		// GlUtils.checkGlError("end draw");
 
@@ -647,19 +602,32 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		else
 			TextRenderer.beginDraw(s, mProjMatrix);
 
-		// s = (float) 1.0 / COORD_MULTIPLIER;
-		// TextRenderer.beginDraw(s, mProjMatrix);
-
 		for (int i = 0; i < tileCnt; i++) {
 			if (!tiles[i].isVisible || tiles[i].texture == null)
 				continue;
 
-			setMatrix(mMVPMatrix, mapPosition, tiles[i], 1, false);
+			setMatrix(mMVPMatrix, tiles[i], 1, false);
 			TextRenderer.drawTile(tiles[i], mMVPMatrix);
 		}
 		TextRenderer.endDraw();
 
-		// TODO call overlay renderer
+		// TODO call overlay renderer here
+
+		// s = 0.5f;
+		// mTileCoords[0] = -s;
+		// mTileCoords[1] = s;
+		// mTileCoords[2] = s;
+		// mTileCoords[3] = s;
+		// mTileCoords[4] = -s;
+		// mTileCoords[5] = -s;
+		// mTileCoords[6] = s;
+		// mTileCoords[7] = -s;
+		//
+		// Matrix.setIdentityM(mMVPMatrix, 0);
+		// // Matrix.scaleM(mMVPMatrix, 0, 0.99f, 0.99f, 1);
+		// // Matrix.multiplyMM(mMVPMatrix, 0, mRotateMatrix, 0, mMVPMatrix, 0);
+		// // Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
+		// PolygonRenderer.debugDraw(mMVPMatrix, mTileCoords);
 
 		if (MapView.debugFrameTime) {
 			GLES20.glFinish();
@@ -670,27 +638,26 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 	// used to not draw a tile twice per frame...
 	private static byte mDrawSerial = 0;
 
-	private static void drawTile(MapPosition mapPosition, MapTile tile) {
+	private static void drawTile(MapTile tile) {
 		// draw parents only once
 		if (tile.lastDraw == mDrawSerial)
 			return;
 
-		float div = 1;
-
-		int diff = mapPosition.zoomLevel - tile.zoomLevel;
-
-		if (diff < 0)
-			div = (1 << -diff);
-		else if (diff > 0)
-			div = (1.0f / (1 << diff));
+		float div = scaleDiv(tile);
+		// float div = 1;
+		// int diff = mapPosition.zoomLevel - tile.zoomLevel;
+		// if (diff < 0)
+		// div = (1 << -diff);
+		// else if (diff > 0)
+		// div = (1.0f / (1 << diff));
 
 		tile.lastDraw = mDrawSerial;
 
-		int z = mapPosition.zoomLevel;
-		float s = mapPosition.scale;
+		int z = mMapPosition.zoomLevel;
+		float s = mMapPosition.scale;
 		float[] mvp = mMVPMatrix;
 
-		setMatrix(mvp, mapPosition, tile, div, true);
+		setMatrix(mvp, tile, div, true);
 
 		GLES20.glPolygonOffset(0, mDrawCount++);
 
@@ -734,7 +701,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 	}
 
 	// TODO could use tile.proxies here
-	private static boolean drawProxyChild(MapPosition mapPosition, MapTile tile) {
+	private static boolean drawProxyChild(MapTile tile) {
 		int drawn = 0;
 		for (int i = 0; i < 4; i++) {
 			if (tile.rel.child[i] == null)
@@ -744,13 +711,13 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 			if (c == null)
 				continue;
 
-			if (!isVisible(mapPosition, c)) {
+			if (!isVisible(c)) {
 				drawn++;
 				continue;
 			}
 
 			if (c.isReady) {
-				drawTile(mapPosition, c);
+				drawTile(c);
 				drawn++;
 			}
 		}
@@ -758,17 +725,17 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 	}
 
 	// TODO could use tile.proxies here
-	private static void drawProxyTile(MapPosition mapPosition, MapTile tile) {
-		int diff = mapPosition.zoomLevel - tile.zoomLevel;
+	private static void drawProxyTile(MapTile tile) {
+		int diff = mMapPosition.zoomLevel - tile.zoomLevel;
 
 		boolean drawn = false;
-		if (mapPosition.scale > 1.5f || diff < 0) {
+		if (mMapPosition.scale > 1.5f || diff < 0) {
 			// prefer drawing children
-			if (!drawProxyChild(mapPosition, tile)) {
+			if (!drawProxyChild(tile)) {
 				if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
 					MapTile t = tile.rel.parent.tile;
 					if (t.isReady) {
-						drawTile(mapPosition, t);
+						drawTile(t);
 						drawn = true;
 					}
 				}
@@ -776,7 +743,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 				if (!drawn && (tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
 					MapTile t = tile.rel.parent.parent.tile;
 					if (t.isReady)
-						drawTile(mapPosition, t);
+						drawTile(t);
 
 				}
 			}
@@ -785,14 +752,14 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 			MapTile t = tile.rel.parent.tile;
 
 			if (t != null && t.isReady) {
-				drawTile(mapPosition, t);
+				drawTile(t);
 
-			} else if (!drawProxyChild(mapPosition, tile)) {
+			} else if (!drawProxyChild(tile)) {
 
 				if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
 					t = tile.rel.parent.parent.tile;
 					if (t.isReady)
-						drawTile(mapPosition, t);
+						drawTile(t);
 				}
 			}
 		}
@@ -814,14 +781,18 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 
 		// Matrix.orthoM(mProjMatrix, 0, -0.5f / mAspect, 0.5f / mAspect, -0.5f,
 		// 0.5f, -1, 1);
+		float s = 0.5f;
+		Matrix.frustumM(mProjMatrix, 0, -s * width, s * width,
+				-s * height, s * height, 1, 2);
+		Matrix.translateM(mProjMatrix, 0, 0, 0, -1);
 
-		Matrix.frustumM(mProjMatrix, 0,
-				-0.5f * width,
-				0.5f * width,
-				-0.5f * height,
-				0.5f * height, 1, 2);
+		// Matrix.invertM(mProjMatrixI, 0, mProjMatrix, 0);
 
-		Matrix.invertM(mProjMatrixI, 0, mProjMatrix, 0);
+		// use this to scale only the view to see which tiles are rendered
+		// s = 1.0f;
+		// Matrix.frustumM(mProjMatrix, 0, -s * width, s * width,
+		// -s * height, s * height, 1, 2);
+		// Matrix.translateM(mProjMatrix, 0, 0, 0, -1);
 
 		// set to zero: we modify the z value with polygon-offset for clipping
 		mProjMatrix[10] = 0;
@@ -869,6 +840,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
 		mMapView.redrawMap();
 	}
 
+	// FIXME this is a bit too spaghetti
 	void clearTiles(int numTiles) {
 		mDrawTiles = new TilesData(numTiles);
 		mNextTiles = new TilesData(numTiles);
diff --git a/src/org/oscim/view/renderer/LineLayer.java b/src/org/oscim/view/renderer/LineLayer.java
index b935dff4..f5b78595 100644
--- a/src/org/oscim/view/renderer/LineLayer.java
+++ b/src/org/oscim/view/renderer/LineLayer.java
@@ -40,8 +40,8 @@ class LineLayer {
 	boolean isOutline;
 	int layer;
 
-	ShortItem pool;
-	protected ShortItem curItem;
+	VertexPoolItem pool;
+	protected VertexPoolItem curItem;
 
 	// number of vertices this layer holds
 	int verticesCnt;
@@ -85,10 +85,10 @@ class LineLayer {
 			squared = true;
 
 		if (pool == null) {
-			pool = curItem = ShortPool.get();
+			pool = curItem = VertexPool.get();
 		}
 
-		ShortItem si = curItem;
+		VertexPoolItem si = curItem;
 		short v[] = si.vertices;
 		int opos = si.used;
 
@@ -137,8 +137,8 @@ class LineLayer {
 			ux = -vy;
 			uy = vx;
 
-			if (opos == ShortItem.SIZE) {
-				si = si.next = ShortPool.get();
+			if (opos == VertexPoolItem.SIZE) {
+				si = si.next = VertexPool.get();
 				v = si.vertices;
 				opos = 0;
 			}
@@ -151,8 +151,8 @@ class LineLayer {
 
 			boolean outside = (x < tmin || x > tmax || y < tmin || y > tmax);
 
-			if (opos == ShortItem.SIZE) {
-				si = si.next = ShortPool.get();
+			if (opos == VertexPoolItem.SIZE) {
+				si = si.next = VertexPool.get();
 				v = si.vertices;
 				opos = 0;
 			}
@@ -170,8 +170,8 @@ class LineLayer {
 				v[opos++] = dx;
 				v[opos++] = dy;
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -181,8 +181,8 @@ class LineLayer {
 				v[opos++] = dx;
 				v[opos++] = dy;
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -195,8 +195,8 @@ class LineLayer {
 				v[opos++] = (short) (2 | ddx & DIR_MASK);
 				v[opos++] = (short) (2 | ddy & DIR_MASK);
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -210,8 +210,8 @@ class LineLayer {
 				v[opos++] = (short) (0 | ddx & DIR_MASK);
 				v[opos++] = (short) (1 | ddy & DIR_MASK);
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -248,8 +248,8 @@ class LineLayer {
 				v[opos++] = dx;
 				v[opos++] = dy;
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -259,8 +259,8 @@ class LineLayer {
 				v[opos++] = dx;
 				v[opos++] = dy;
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -334,8 +334,8 @@ class LineLayer {
 				ddx = (int) (ux * DIR_SCALE);
 				ddy = (int) (uy * DIR_SCALE);
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -345,8 +345,8 @@ class LineLayer {
 				v[opos++] = (short) (0 | ddx & DIR_MASK);
 				v[opos++] = (short) (1 | ddy & DIR_MASK);
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -375,8 +375,8 @@ class LineLayer {
 
 			outside = (x < tmin || x > tmax || y < tmin || y > tmax);
 
-			if (opos == ShortItem.SIZE) {
-				si.next = ShortPool.get();
+			if (opos == VertexPoolItem.SIZE) {
+				si.next = VertexPool.get();
 				si = si.next;
 				opos = 0;
 				v = si.vertices;
@@ -394,8 +394,8 @@ class LineLayer {
 				v[opos++] = (short) (0 | ddx & DIR_MASK);
 				v[opos++] = (short) (1 | ddy & DIR_MASK);
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -405,8 +405,8 @@ class LineLayer {
 				v[opos++] = (short) (2 | -ddx & DIR_MASK);
 				v[opos++] = (short) (1 | -ddy & DIR_MASK);
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -422,8 +422,8 @@ class LineLayer {
 				v[opos++] = dx;
 				v[opos++] = dy;
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -439,8 +439,8 @@ class LineLayer {
 				v[opos++] = dx;
 				v[opos++] = dy;
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -470,8 +470,8 @@ class LineLayer {
 				v[opos++] = (short) (0 | ddx & DIR_MASK);
 				v[opos++] = (short) (1 | ddy & DIR_MASK);
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
@@ -487,8 +487,8 @@ class LineLayer {
 				v[opos++] = dx;
 				v[opos++] = dy;
 
-				if (opos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (opos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					opos = 0;
 				}
diff --git a/src/org/oscim/view/renderer/LineRenderer.java b/src/org/oscim/view/renderer/LineRenderer.java
index e44326cd..33220e36 100644
--- a/src/org/oscim/view/renderer/LineRenderer.java
+++ b/src/org/oscim/view/renderer/LineRenderer.java
@@ -183,18 +183,18 @@ class LineRenderer {
 
 	static void compileLayerData(LineLayer layers, ShortBuffer sbuf) {
 		int pos = 0;
-		ShortItem last = null, items = null;
+		VertexPoolItem last = null, items = null;
 
 		for (LineLayer l = layers; l != null; l = l.next) {
 			if (l.isOutline)
 				continue;
 
-			for (ShortItem item = l.pool; item != null; item = item.next) {
+			for (VertexPoolItem item = l.pool; item != null; item = item.next) {
 
 				if (item.next == null) {
 					sbuf.put(item.vertices, 0, item.used);
 				} else {
-					// item.used = ShortItem.SIZE;
+					// item.used = VertexPoolItem.SIZE;
 					sbuf.put(item.vertices);
 				}
 
@@ -213,7 +213,7 @@ class LineRenderer {
 			l.curItem = null;
 		}
 
-		ShortPool.add(items);
+		VertexPool.add(items);
 	}
 
 	// @SuppressLint("UseValueOf")
@@ -310,7 +310,7 @@ class LineRenderer {
 	static void clear(LineLayer layer) {
 		for (LineLayer l = layer; l != null; l = l.next) {
 			if (l.pool != null) {
-				ShortPool.add(l.pool);
+				VertexPool.add(l.pool);
 				l.pool = null;
 				l.curItem = null;
 			}
diff --git a/src/org/oscim/view/renderer/MapRenderer.java b/src/org/oscim/view/renderer/MapRenderer.java
index 98a5d47f..6392bb43 100644
--- a/src/org/oscim/view/renderer/MapRenderer.java
+++ b/src/org/oscim/view/renderer/MapRenderer.java
@@ -8,7 +8,7 @@
  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
+ * 
  * You should have received a copy of the GNU Lesser General Public License along with
  * this program. If not, see <http://www.gnu.org/licenses/>.
  */
@@ -17,21 +17,21 @@ package org.oscim.view.renderer;
 import java.util.ArrayList;
 import java.util.Collections;
 
-import org.oscim.core.MapPosition;
 import org.oscim.core.MercatorProjection;
 import org.oscim.core.Tile;
 import org.oscim.database.MapInfo;
 import org.oscim.theme.RenderTheme;
 import org.oscim.utils.GlConfigChooser;
+import org.oscim.view.MapPosition;
 import org.oscim.view.MapView;
 import org.oscim.view.generator.JobTile;
-import org.oscim.view.renderer.GLRenderer.TilesData;
 
 import android.content.Context;
 import android.opengl.GLSurfaceView;
 import android.util.FloatMath;
 import android.util.Log;
 
+// FIXME to many 'Renderer', this one needs a better name.. TileLoader?
 public class MapRenderer extends GLSurfaceView {
 	private final static String TAG = "MapRenderer";
 	private GLRenderer mRenderer;
@@ -45,7 +45,7 @@ public class MapRenderer extends GLSurfaceView {
 
 	// all tiles currently referenced
 	private static ArrayList<MapTile> mTiles;
-	// private static ArrayList<MapTile> mTilesActive;
+
 	// tiles that have new data to upload, see passTile()
 	private static ArrayList<MapTile> mTilesLoaded;
 
@@ -59,9 +59,20 @@ public class MapRenderer extends GLSurfaceView {
 	// private static MapPosition mCurPosition, mDrawPosition;
 	private static int mWidth = 0, mHeight = 0;
 
+	// used for passing tiles to be rendered from TileLoader(Main-Thread) to
+	// GLThread
+	static final class TilesData {
+		int cnt = 0;
+		final MapTile[] tiles;
+
+		TilesData(int numTiles) {
+			tiles = new MapTile[numTiles];
+		}
+	}
+
 	private static TilesData mCurrentTiles;
 
-	// map zoom-level to available zoom-levels in MapDatabase
+	// maps zoom-level to available zoom-levels in MapDatabase
 	// e.g. 16->16, 15->16, 14->13, 13->13, 12->13,....
 	private static int[] mZoomLevels;
 
@@ -85,7 +96,7 @@ public class MapRenderer extends GLSurfaceView {
 		mTiles = new ArrayList<MapTile>();
 		mTilesLoaded = new ArrayList<MapTile>(30);
 
-		ShortPool.init();
+		VertexPool.init();
 		QuadTree.init();
 
 		mInitial = true;
@@ -97,13 +108,10 @@ public class MapRenderer extends GLSurfaceView {
 	 * loading by TileGenerator class
 	 * 
 	 * @param clear
-	 *            ...
+	 *            whether to clear and reload all tiles
 	 */
-
 	public synchronized void updateMap(boolean clear) {
-
 		boolean changedPos = false;
-		boolean changedZoom = false;
 
 		if (mMapView == null)
 			return;
@@ -155,24 +163,20 @@ public class MapRenderer extends GLSurfaceView {
 
 		int zdir = 0;
 		if (mInitial || mPrevZoom != zoomLevel) {
-			changedZoom = true;
-			mPrevScale = scale;
-		}
-		else if (tileX != mTileX || tileY != mTileY) {
-			if (mPrevScale - scale > 0 && scale > 1.2)
-				zdir = 1;
-			mPrevScale = scale;
 			changedPos = true;
-		}
-		else if (mPrevScale - scale > 0.2 || mPrevScale - scale < -0.2) {
+
+		} else if (tileX != mTileX || tileY != mTileY) {
+			if (mPrevScale - scale > 0 && scale > 1.2)
+				zdir = 1;
+			changedPos = true;
+
+		} else if (mPrevScale - scale > 0.2 || mPrevScale - scale < -0.2) {
 			if (mPrevScale - scale > 0 && scale > 1.2)
 				zdir = 1;
-			mPrevScale = scale;
 			changedPos = true;
 		}
 
 		if (mInitial) {
-			// mCurPosition = mapPosition;
 			mInitial = false;
 		}
 
@@ -180,30 +184,19 @@ public class MapRenderer extends GLSurfaceView {
 		mTileY = tileY;
 		mPrevZoom = zoomLevel;
 
-		GLRenderer.updatePosition(mapPosition);
+		// GLRenderer.updatePosition(mapPosition);
+
 		if (!MapView.debugFrameTime)
 			requestRender();
 
-		if (changedZoom || changedPos) {
-			// need to update visible list first when zoom level changes
-			// as scaling is relative to the tiles of current zoom-level
+		if (changedPos) {
+			mPrevScale = scale;
+
 			updateVisibleList(mapPosition, zdir);
 
 			if (!MapView.debugFrameTime)
 				requestRender();
-		}
-		// else {
-		// // pass new position to glThread
-		// GLRenderer.updatePosition(mapPosition);
-		// }
 
-		// if (!MapView.debugFrameTime)
-		// requestRender();
-
-		// if (changedPos)
-		// updateVisibleList(mapPosition, zdir);
-
-		if (changedPos || changedZoom) {
 			int remove = mTiles.size() - GLRenderer.CACHE_TILES;
 			if (remove > 50)
 				limitCache(mapPosition, remove);
@@ -256,15 +249,15 @@ public class MapRenderer extends GLSurfaceView {
 			// check MapDatabase zoom-level-mapping
 			if (mZoomLevels[zoomLevel] == 0) {
 				mCurrentTiles.cnt = 0;
-				mCurrentTiles = GLRenderer.updateTiles(mapPosition, mCurrentTiles);
+				mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
 				return;
 			}
 
 			if (mZoomLevels[zoomLevel] > zoomLevel) {
 				fetchChildren = true;
 				fetchProxy = true;
-			}
-			else if (mZoomLevels[zoomLevel] < zoomLevel) {
+
+			} else if (mZoomLevels[zoomLevel] < zoomLevel) {
 				fetchParent = true;
 				fetchProxy = true;
 			}
@@ -285,12 +278,12 @@ public class MapRenderer extends GLSurfaceView {
 					mTiles.add(tile);
 				}
 
-				mCurrentTiles.tiles[tiles++] = tile;
-
-				if (!fetchProxy && !(tile.isLoading || tile.newData || tile.isReady)) {
+				if (!fetchProxy && !tile.isActive()) {
 					mJobList.add(tile);
 				}
 
+				mCurrentTiles.tiles[tiles++] = tile;
+
 				if (fetchChildren) {
 					byte z = (byte) (zoomLevel + 1);
 					for (int i = 0; i < 4; i++) {
@@ -306,7 +299,7 @@ public class MapRenderer extends GLSurfaceView {
 							mTiles.add(c);
 						}
 
-						if (!(c.isLoading || c.newData || c.isReady)) {
+						if (!c.isActive()) {
 							mJobList.add(c);
 						}
 					}
@@ -314,18 +307,18 @@ public class MapRenderer extends GLSurfaceView {
 
 				if (fetchParent || (!fetchProxy && zdir > 0 && zoomLevel > 0)) {
 					// prefetch parent
-					MapTile parent = tile.rel.parent.tile;
+					MapTile p = tile.rel.parent.tile;
 
-					if (parent == null) {
-						parent = new MapTile(xx >> 1, yy >> 1, (byte) (zoomLevel - 1));
+					if (p == null) {
+						p = new MapTile(xx >> 1, yy >> 1, (byte) (zoomLevel - 1));
 
-						QuadTree.add(parent);
-						mTiles.add(parent);
-					}
+						QuadTree.add(p);
+						mTiles.add(p);
+						mJobList.add(p);
 
-					if (!(parent.isLoading || parent.isReady || parent.newData)) {
-						if (!mJobList.contains(parent))
-							mJobList.add(parent);
+					} else if (!p.isActive()) {
+						if (!mJobList.contains(p))
+							mJobList.add(p);
 					}
 				}
 			}
@@ -333,7 +326,7 @@ public class MapRenderer extends GLSurfaceView {
 
 		// pass new tile list to glThread
 		mCurrentTiles.cnt = tiles;
-		mCurrentTiles = GLRenderer.updateTiles(mapPosition, mCurrentTiles);
+		mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
 
 		// note: this sets isLoading == true for all job tiles
 		if (mJobList.size() > 0) {
@@ -366,8 +359,7 @@ public class MapRenderer extends GLSurfaceView {
 		QuadTree.remove(t);
 	}
 
-	private static void updateTileDistances(ArrayList<?> tiles,
-			MapPosition mapPosition) {
+	private static void updateTileDistances(ArrayList<?> tiles, MapPosition mapPosition) {
 		int h = (Tile.TILE_SIZE >> 1);
 		byte zoom = mapPosition.zoomLevel;
 		long x = (long) mapPosition.x;
@@ -422,18 +414,17 @@ public class MapRenderer extends GLSurfaceView {
 
 		// remove orphaned tiles
 		for (int i = 0; i < size;) {
-			MapTile cur = mTiles.get(i);
+			MapTile t = mTiles.get(i);
 			// make sure tile cannot be used by GL or MapWorker Thread
-			if (!cur.isLocked() && !cur.isLoading && !cur.newData && !cur.isReady) {
-
-				clearTile(cur);
+			if (t.isLocked() || t.isActive()) {
+				i++;
+			} else {
+				// Log.d(TAG, "remove empty tile" + cur);
+				clearTile(t);
 				mTiles.remove(i);
 				removes--;
 				size--;
-				// Log.d(TAG, "remove empty tile" + cur);
-				continue;
 			}
-			i++;
 		}
 
 		// Log.d(TAG, "remove tiles: " + removes + " " + size);
@@ -451,7 +442,7 @@ public class MapRenderer extends GLSurfaceView {
 			synchronized (t) {
 				if (t.isLocked()) {
 					// dont remove tile used by renderthread
-					Log.d(TAG, "X not removing " + t + " " + t.isActive + " "
+					Log.d(TAG, "X not removing " + t + " " + t.isLocked + " "
 							+ t.distance);
 
 					mTiles.add(t);
@@ -478,7 +469,7 @@ public class MapRenderer extends GLSurfaceView {
 
 		synchronized (mTilesLoaded) {
 
-			// remove uploaded tiles
+			// remove tiles uploaded to vbo
 			for (int i = 0; i < size;) {
 				MapTile t = mTilesLoaded.get(i);
 				// rel == null means tile is already removed by limitCache
@@ -535,8 +526,7 @@ public class MapRenderer extends GLSurfaceView {
 
 		if (!tile.isLoading) {
 			// no one should be able to use this tile now, mapgenerator passed
-			// it,
-			// glthread does nothing until newdata is set.
+			// it, glthread does nothing until newdata is set.
 			Log.d(TAG, "passTile: canceled " + tile);
 			synchronized (mTilesLoaded) {
 				mTilesLoaded.add(tile);
diff --git a/src/org/oscim/view/renderer/MapTile.java b/src/org/oscim/view/renderer/MapTile.java
index cdf104eb..a8845808 100644
--- a/src/org/oscim/view/renderer/MapTile.java
+++ b/src/org/oscim/view/renderer/MapTile.java
@@ -41,7 +41,7 @@ class MapTile extends JobTile {
 	/**
 	 * tile is used by render thread. set by updateVisibleList (main thread).
 	 */
-	boolean isActive;
+	boolean isLocked;
 
 	/**
 	 * tile has new data to upload to gl
@@ -74,13 +74,16 @@ class MapTile extends JobTile {
 	// counting the tiles that use this tile as proxy
 	byte refs;
 
+	boolean isActive() {
+		return isLoading || newData || isReady;
+	}
+
 	boolean isLocked() {
-		return isActive || refs > 0;
+		return isLocked || refs > 0;
 	}
 
 	void lock() {
-
-		isActive = true;
+		isLocked = true;
 
 		if (isReady || newData)
 			return;
@@ -110,7 +113,7 @@ class MapTile extends JobTile {
 	}
 
 	void unlock() {
-		isActive = false;
+		isLocked = false;
 
 		if (proxies == 0)
 			return;
diff --git a/src/org/oscim/view/renderer/PolygonLayer.java b/src/org/oscim/view/renderer/PolygonLayer.java
index aa310123..c25328b2 100644
--- a/src/org/oscim/view/renderer/PolygonLayer.java
+++ b/src/org/oscim/view/renderer/PolygonLayer.java
@@ -23,8 +23,8 @@ class PolygonLayer {
 	PolygonLayer next;
 	Area area;
 
-	ShortItem pool;
-	protected ShortItem curItem;
+	VertexPoolItem pool;
+	protected VertexPoolItem curItem;
 	int verticesCnt;
 	int offset;
 
@@ -33,14 +33,14 @@ class PolygonLayer {
 	PolygonLayer(int layer, Area area) {
 		this.layer = layer;
 		this.area = area;
-		curItem = ShortPool.get();
+		curItem = VertexPool.get();
 		pool = curItem;
 	}
 
 	void addPolygon(float[] points, short[] index) {
 		short center = (short) ((Tile.TILE_SIZE >> 1) * S);
 
-		ShortItem si = curItem;
+		VertexPoolItem si = curItem;
 		short[] v = si.vertices;
 		int outPos = si.used;
 
@@ -59,8 +59,8 @@ class PolygonLayer {
 
 			int inPos = pos;
 
-			if (outPos == ShortItem.SIZE) {
-				si = si.next = ShortPool.get();
+			if (outPos == VertexPoolItem.SIZE) {
+				si = si.next = VertexPool.get();
 				v = si.vertices;
 				outPos = 0;
 			}
@@ -69,8 +69,8 @@ class PolygonLayer {
 			v[outPos++] = center;
 
 			for (int j = 0; j < length; j += 2) {
-				if (outPos == ShortItem.SIZE) {
-					si = si.next = ShortPool.get();
+				if (outPos == VertexPoolItem.SIZE) {
+					si = si.next = VertexPool.get();
 					v = si.vertices;
 					outPos = 0;
 				}
@@ -78,8 +78,8 @@ class PolygonLayer {
 				v[outPos++] = (short) (points[inPos++] * S);
 			}
 
-			if (outPos == ShortItem.SIZE) {
-				si = si.next = ShortPool.get();
+			if (outPos == VertexPoolItem.SIZE) {
+				si = si.next = VertexPool.get();
 				v = si.vertices;
 				outPos = 0;
 			}
diff --git a/src/org/oscim/view/renderer/PolygonRenderer.java b/src/org/oscim/view/renderer/PolygonRenderer.java
index 137e5245..a423e25e 100644
--- a/src/org/oscim/view/renderer/PolygonRenderer.java
+++ b/src/org/oscim/view/renderer/PolygonRenderer.java
@@ -35,6 +35,9 @@ import static android.opengl.GLES20.glUniformMatrix4fv;
 import static android.opengl.GLES20.glUseProgram;
 import static android.opengl.GLES20.glVertexAttribPointer;
 
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
 import java.nio.ShortBuffer;
 
 import org.oscim.utils.GlUtils;
@@ -257,7 +260,7 @@ class PolygonRenderer {
 		if (mCount > 0)
 			fillPolygons(zoom, scale);
 
-		//
+		// maybe reset start when only few layers left in stencil buffer
 		// if (mCount > 5){
 		// mCount = 0;
 		// mStart = 0;
@@ -273,6 +276,35 @@ class PolygonRenderer {
 		return l;
 	}
 
+	private static float[] debugFillColor = { 0.3f, 0.0f, 0.0f, 0.3f };
+
+	private static ByteBuffer mDebugFill;
+
+	static void debugDraw(float[] matrix, float[] coords) {
+
+		mDebugFill = ByteBuffer.allocateDirect(32).order(ByteOrder.nativeOrder());
+		FloatBuffer buf = mDebugFill.asFloatBuffer();
+		buf.put(coords);
+
+		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+
+		mDebugFill.position(0);
+		glUseProgram(polygonProgram);
+		GLES20.glEnableVertexAttribArray(hPolygonVertexPosition);
+
+		glVertexAttribPointer(hPolygonVertexPosition, 2, GLES20.GL_FLOAT,
+				false, 0, mDebugFill);
+
+		glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
+
+		glUniform4fv(hPolygonColor, 1, debugFillColor, 0);
+
+		glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+
+		GlUtils.checkGlError("draw debug");
+		GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);
+	}
+
 	static void drawDepthClip() {
 		glColorMask(false, false, false, false);
 		GLES20.glDepthMask(true);
@@ -299,16 +331,16 @@ class PolygonRenderer {
 	static void compileLayerData(PolygonLayer layers, ShortBuffer sbuf) {
 		int pos = 4;
 
-		ShortItem last = null, items = null;
+		VertexPoolItem last = null, items = null;
 
 		for (PolygonLayer l = layers; l != null; l = l.next) {
 
-			for (ShortItem item = l.pool; item != null; item = item.next) {
+			for (VertexPoolItem item = l.pool; item != null; item = item.next) {
 
 				if (item.next == null) {
 					sbuf.put(item.vertices, 0, item.used);
 				} else {
-					// item.used = ShortItem.SIZE;
+					// item.used = VertexPoolItem.SIZE;
 					sbuf.put(item.vertices);
 				}
 
@@ -326,13 +358,13 @@ class PolygonRenderer {
 			l.pool = null;
 		}
 
-		ShortPool.add(items);
+		VertexPool.add(items);
 	}
 
 	static void clear(PolygonLayer layers) {
 		for (PolygonLayer l = layers; l != null; l = l.next) {
 			if (l.pool != null)
-				ShortPool.add(l.pool);
+				VertexPool.add(l.pool);
 		}
 	}
 }
diff --git a/src/org/oscim/view/renderer/ScanBox.java b/src/org/oscim/view/renderer/ScanBox.java
new file mode 100644
index 00000000..b5d7093e
--- /dev/null
+++ b/src/org/oscim/view/renderer/ScanBox.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2012 Hannes Janetzek
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* ported from Polymaps: Layer.js */
+
+package org.oscim.view.renderer;
+
+import org.oscim.view.renderer.MapRenderer.TilesData;
+
+import android.util.FloatMath;
+
+public class ScanBox {
+
+	interface Callback {
+		void call(MapTile tile);
+	}
+
+	class SetVisible implements Callback {
+
+		@Override
+		public void call(MapTile tile) {
+			tile.isVisible = true;
+		}
+	}
+
+	static class Edge {
+		float x0, y0, x1, y1, dx, dy;
+
+		void set(float x0, float y0, float x1, float y1) {
+			if (y0 <= y1) {
+				this.x0 = x0;
+				this.y0 = y0;
+				this.x1 = x1;
+				this.y1 = y1;
+				this.dx = x1 - x0;
+				this.dy = y1 - y0;
+			} else {
+				this.x0 = x1;
+				this.y0 = y1;
+				this.x1 = x0;
+				this.y1 = y0;
+				this.dx = x0 - x1;
+				this.dy = y0 - y1;
+			}
+		}
+	}
+
+	static Edge ab = new Edge();
+	static Edge bc = new Edge();
+	static Edge ca = new Edge();
+
+	static void scanSpans(Edge e0, Edge e1, float ymin, float ymax) {
+
+		// sort edge by x-coordinate
+		if (e0.x0 == e1.x0 && e0.y0 == e1.y0) {
+			if (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) {
+				Edge t = e0;
+				e0 = e1;
+				e1 = t;
+			}
+		} else {
+			if (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0) {
+				Edge t = e0;
+				e0 = e1;
+				e1 = t;
+			}
+		}
+
+		float m0 = e0.dx / e0.dy;
+		float m1 = e1.dx / e1.dy;
+
+		int d0 = e0.dx > 0 ? 1 : 0;// use y + 1 to compute x0
+		int d1 = e1.dx < 0 ? 1 : 0; // use y + 1 to compute x1
+
+		float x0, x1;
+
+		int y = (int) Math.max(ymin, FloatMath.floor(e1.y0));
+		int bottom = (int) Math.min(ymax, FloatMath.ceil(e1.y1));
+
+		for (; y < bottom; y++) {
+			// float x0 = (m0 * Math.min(e0.dy, y + d0 - e0.y0) + e0.x0);
+			// float x1 = (m1 * Math.min(e1.dy, y + d1 - e1.y0) + e1.x0);
+
+			x0 = y + d0 - e0.y0;
+			if (e0.dy < x0)
+				x0 = e0.dy;
+
+			x0 = m0 * x0 + e0.x0;
+
+			if (x0 < 0)
+				x0 = 0;
+			else
+				x0 = FloatMath.ceil(x0);
+
+			x1 = y + d1 - e1.y0;
+			if (e1.dy < x1)
+				x1 = e1.dy;
+
+			x1 = m1 * x1 + e1.x0;
+
+			if (x1 < 0)
+				x1 = 0;
+			else
+				x1 = FloatMath.floor(x1);
+
+			setVisible(y, (int) x1, (int) x0);
+
+			// setVisible(y, (int) (x1 - 0.5f), (int) (x0 + 0.5f));
+		}
+	}
+
+	static void scanTriangle(float ymin, float ymax) {
+
+		if (ab.dy > bc.dy) {
+			Edge t = ab;
+			ab = bc;
+			bc = t;
+		}
+		if (ab.dy > ca.dy) {
+			Edge t = ab;
+			ab = ca;
+			ca = t;
+		}
+		if (bc.dy > ca.dy) {
+			Edge t = bc;
+			bc = ca;
+			ca = t;
+		}
+
+		if (ab.dy != 0)
+			scanSpans(ca, ab, ymin, ymax);
+		if (bc.dy != 0)
+			scanSpans(ca, bc, ymin, ymax);
+	}
+
+	public static void scan(float[] coords, TilesData tiles, int max) {
+		sTiles = tiles;
+		cntDoubles = 0;
+		ab.set(coords[0], coords[1], coords[2], coords[3]);
+		bc.set(coords[2], coords[3], coords[4], coords[5]);
+		ca.set(coords[4], coords[5], coords[0], coords[1]);
+
+		scanTriangle(0, max);
+		// Log.d("..", ">doubles " + cntDoubles);
+		ab.set(coords[4], coords[5], coords[6], coords[7]);
+		bc.set(coords[6], coords[7], coords[0], coords[1]);
+		ca.set(coords[0], coords[1], coords[4], coords[5]);
+
+		scanTriangle(0, max);
+
+		// Log.d("..", "<doubles " + cntDoubles);
+	}
+
+	private static TilesData sTiles;
+	private static int cntDoubles;
+
+	private static void setVisible(int y, int x1, int x2) {
+
+		MapTile[] tiles = sTiles.tiles;
+		for (int i = 0, n = sTiles.cnt; i < n; i++) {
+			if (tiles[i].tileY == y) {
+				if (tiles[i].tileX >= x1 && tiles[i].tileX < x2) {
+					// if (tiles[i].isVisible) {
+					// Log.d("..", ">>>" + y + " " + tiles[i].tileX);
+					// cntDoubles++;
+					// }
+					tiles[i].isVisible = true;
+				}
+			}
+		}
+	}
+}
diff --git a/src/org/oscim/view/renderer/TextRenderer.java b/src/org/oscim/view/renderer/TextRenderer.java
index 8fd79285..eba3e990 100644
--- a/src/org/oscim/view/renderer/TextRenderer.java
+++ b/src/org/oscim/view/renderer/TextRenderer.java
@@ -192,7 +192,7 @@ public class TextRenderer {
 			if (tex.tile == null)
 				break;
 
-			if (!tex.tile.isActive)
+			if (!tex.tile.isLocked)
 				break;
 
 			tex = null;
@@ -412,7 +412,7 @@ public class TextRenderer {
 
 		for (int i = 0; i < mTextures.length; i++) {
 			tex = mTextures[i];
-			if (tex.tile == null || !tex.tile.isActive)
+			if (tex.tile == null || !tex.tile.isLocked)
 				continue;
 
 			mShortBuffer.put(tex.vertices, 0, tex.length);
diff --git a/src/org/oscim/view/renderer/ShortPool.java b/src/org/oscim/view/renderer/VertexPool.java
similarity index 75%
rename from src/org/oscim/view/renderer/ShortPool.java
rename to src/org/oscim/view/renderer/VertexPool.java
index ccfae746..e3a52833 100644
--- a/src/org/oscim/view/renderer/ShortPool.java
+++ b/src/org/oscim/view/renderer/VertexPool.java
@@ -16,10 +16,10 @@ package org.oscim.view.renderer;
 
 import android.util.Log;
 
-public class ShortPool {
+public class VertexPool {
 	private static final int POOL_LIMIT = 6000;
 
-	static private ShortItem pool = null;
+	static private VertexPoolItem pool = null;
 	static private int count = 0;
 	static private int countAll = 0;
 
@@ -29,14 +29,14 @@ public class ShortPool {
 		pool = null;
 	}
 
-	static synchronized ShortItem get() {
+	static synchronized VertexPoolItem get() {
 
 		if (pool == null && count > 0) {
-			Log.d("ShortPool", "XXX wrong count: " + count);
+			Log.d("VertexPool", "XXX wrong count: " + count);
 		}
 		if (pool == null) {
 			countAll++;
-			return new ShortItem();
+			return new VertexPoolItem();
 		}
 
 		count--;
@@ -44,14 +44,14 @@ public class ShortPool {
 		if (count < 0) {
 			int c = 0;
 
-			for (ShortItem tmp = pool; tmp != null; tmp = tmp.next)
+			for (VertexPoolItem tmp = pool; tmp != null; tmp = tmp.next)
 				c++;
 
-			Log.d("ShortPool", "XXX wrong count: " + count + " left" + c);
-			return new ShortItem();
+			Log.d("VertexPool", "XXX wrong count: " + count + " left" + c);
+			return new VertexPoolItem();
 		}
 
-		ShortItem it = pool;
+		VertexPoolItem it = pool;
 		pool = pool.next;
 		it.used = 0;
 		it.next = null;
@@ -61,7 +61,7 @@ public class ShortPool {
 	// private static float load = 1.0f;
 	// private static int loadCount = 0;
 
-	static synchronized void add(ShortItem items) {
+	static synchronized void add(VertexPoolItem items) {
 		if (items == null)
 			return;
 
@@ -71,11 +71,11 @@ public class ShortPool {
 		// limit pool items
 		if (countAll < POOL_LIMIT) {
 
-			ShortItem last = items;
+			VertexPoolItem last = items;
 
 			while (true) {
 				count++;
-				// load += (float) last.used / ShortItem.SIZE;
+				// load += (float) last.used / VertexPoolItem.SIZE;
 				// loadCount++;
 
 				if (last.next == null)
@@ -91,14 +91,14 @@ public class ShortPool {
 
 		} else {
 			// int cleared = 0;
-			ShortItem prev, tmp = items;
+			VertexPoolItem prev, tmp = items;
 			while (tmp != null) {
 				prev = tmp;
 				tmp = tmp.next;
 
 				countAll--;
 
-				// load += (float) prev.used / ShortItem.SIZE;
+				// load += (float) prev.used / VertexPoolItem.SIZE;
 				// loadCount++;
 
 				prev.next = null;
diff --git a/src/org/oscim/view/renderer/ShortItem.java b/src/org/oscim/view/renderer/VertexPoolItem.java
similarity index 92%
rename from src/org/oscim/view/renderer/ShortItem.java
rename to src/org/oscim/view/renderer/VertexPoolItem.java
index a94b89d1..0d4cfdbe 100644
--- a/src/org/oscim/view/renderer/ShortItem.java
+++ b/src/org/oscim/view/renderer/VertexPoolItem.java
@@ -14,12 +14,12 @@
  */
 package org.oscim.view.renderer;
 
-public class ShortItem {
+public class VertexPoolItem {
 	final short[] vertices;
 	int used;
-	ShortItem next;
+	VertexPoolItem next;
 
-	ShortItem() {
+	VertexPoolItem() {
 		vertices = new short[SIZE];
 		used = 0;
 	}