- adding MapDatabase backend for our TileStache provider

- fixing some renering bugs on nexus phone
and some refactoring and cleanup
This commit is contained in:
Hannes Janetzek 2012-08-07 03:04:39 +02:00
parent c5c952bf14
commit 124624785d
43 changed files with 2287 additions and 1779 deletions

View File

@ -12,14 +12,15 @@
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="15" />
android:targetSdkVersion="16" />
<application
android:icon="@drawable/globe2"
android:label="@string/application_name"
android:theme="@style/Theme.TileMap" >
<activity android:name="org.mapsforge.app.TileMap" >
android:label="@string/application_name"
android:theme="@style/Theme.TileMap" >
<activity
android:name="org.mapsforge.app.TileMap"
android:configChanges="orientation|screenSize" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -28,6 +29,6 @@
</activity>
<activity android:name=".preferences.EditPreferences" />
<activity android:name=".filepicker.FilePicker" />
</application>
</manifest>
</application>
</manifest>

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mainView"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<org.mapsforge.android.MapView
android:id="@+id/mapView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<ToggleButton
android:id="@+id/snapToLocationView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="10dip"
android:layout_marginTop="10dip"
android:background="@drawable/snap_to_position"
android:textOff=""
android:textOn=""
android:visibility="gone" />
</RelativeLayout>

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/menu_position"
android:icon="@drawable/ic_menu_mylocation"
android:showAsAction="always"
android:title="@string/menu_position">
<menu>
<item
android:id="@+id/menu_position_my_location_enable"
android:title="@string/menu_position_my_location_enable"/>
<item
android:id="@+id/menu_position_my_location_disable"
android:title="@string/menu_position_my_location_disable"/>
<item
android:id="@+id/menu_position_last_known"
android:title="@string/menu_position_last_known"/>
<item
android:id="@+id/menu_position_enter_coordinates"
android:title="@string/menu_position_enter_coordinates"/>
<item
android:id="@+id/menu_position_map_center"
android:title="@string/menu_position_map_file_center"/>
</menu>
</item>
<item
android:id="@+id/menu_options"
android:icon="@drawable/ic_menu_options"
android:showAsAction="always"
android:title="@string/menu_options">
<menu>
<!-- android:icon="@drawable/ic_menu_preferences" -->
<item
android:id="@+id/menu_preferences"
android:showAsAction="never"
android:title="@string/menu_preferences"/>
<!-- android:icon="@drawable/ic_menu_mapmode" -->
<!-- android:icon="@drawable/ic_menu_archive" -->
<item
android:id="@+id/menu_mapfile"
android:showAsAction="never"
android:title="@string/menu_mapfile"/>
<!-- <item
android:id="@+id/menu_info_map_file"
android:title="@string/menu_info_map_file"/> -->
</menu>
</item>
<item
android:id="@+id/menu_render_theme"
android:showAsAction="never"
android:title="@string/menu_render_theme">
<menu>
<item
android:id="@+id/menu_render_theme_osmarender"
android:title="@string/menu_render_theme_osmarender"/>
<item
android:id="@+id/menu_render_theme_select_file"
android:title="@string/menu_render_theme_select_file"/>
</menu>
</item>
</menu>

View File

@ -3,6 +3,7 @@
<string-array name="preferences_map_generator_values">
<item>Mapfile</item>
<item>PostGIS</item>
<item>OpenScienceMap</item>
</string-array>
<string-array name="preferences_scale_bar_unit_values">

View File

@ -3,6 +3,7 @@
<string-array name="preferences_map_generator_values">
<item>Mapfile</item>
<item>PostGIS</item>
<item>OpenScienceMap</item>
</string-array>
<string-array name="preferences_text_scale_values">

View File

@ -3,6 +3,7 @@
<string-array name="preferences_map_generator_values">
<item>Mapfile</item>
<item>PostGIS</item>
<item>OpenScienceMap</item>
</string-array>
<string-array name="preferences_text_scale_values">

View File

@ -3,6 +3,7 @@
<string-array name="preferences_map_database_keys">
<item>MAP_READER</item>
<item>POSTGIS_READER</item>
<item>PBMAP_READER</item>
</string-array>
<string name="preferences_map_database_default">POSTGIS_READER</string>

View File

@ -3,6 +3,7 @@
<string-array name="preferences_map_generator_values">
<item>Mapfile</item>
<item>PostGIS</item>
<item>OpenScienceMap</item>
</string-array>
<string-array name="preferences_scale_bar_unit_values">

View File

@ -14,6 +14,7 @@
*/
package org.mapsforge.android;
import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import android.opengl.GLSurfaceView;
@ -21,7 +22,7 @@ import android.opengl.GLSurfaceView;
/**
*
*/
public interface MapRenderer extends GLSurfaceView.Renderer {
public interface IMapRenderer extends GLSurfaceView.Renderer {
/**
* @param mapGeneratorJob
@ -31,9 +32,8 @@ public interface MapRenderer extends GLSurfaceView.Renderer {
public boolean passTile(MapGeneratorJob mapGeneratorJob);
/**
* @return true when tile passed to renderer is processed false otherwise.
* used to lock overwriting resources passed with the tile
* (e.g. lock until bitmap is loaded to texture)
* @return true when tile passed to renderer is processed false otherwise. used to lock overwriting resources passed
* with the tile (e.g. lock until bitmap is loaded to texture)
*/
public boolean processedTile();
@ -44,4 +44,6 @@ public interface MapRenderer extends GLSurfaceView.Renderer {
* ...
*/
public void redrawTiles(boolean clear);
public IMapGenerator createMapGenerator();
}

View File

@ -16,25 +16,35 @@ package org.mapsforge.android;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import javax.xml.parsers.ParserConfigurationException;
import org.mapsforge.android.input.TouchHandler;
import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.JobParameters;
import org.mapsforge.android.mapgenerator.JobQueue;
import org.mapsforge.android.mapgenerator.JobTheme;
import org.mapsforge.android.mapgenerator.MapDatabaseFactory;
import org.mapsforge.android.mapgenerator.MapDatabaseInternal;
import org.mapsforge.android.mapgenerator.MapGeneratorFactory;
import org.mapsforge.android.mapgenerator.MapGeneratorInternal;
import org.mapsforge.android.mapgenerator.MapDatabases;
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.mapgenerator.MapRendererFactory;
import org.mapsforge.android.mapgenerator.MapRenderers;
import org.mapsforge.android.mapgenerator.MapWorker;
import org.mapsforge.android.mapgenerator.Theme;
import org.mapsforge.android.rendertheme.ExternalRenderTheme;
import org.mapsforge.android.rendertheme.InternalRenderTheme;
import org.mapsforge.android.rendertheme.RenderTheme;
import org.mapsforge.android.rendertheme.RenderThemeHandler;
import org.mapsforge.android.utils.GlConfigChooser;
import org.mapsforge.core.GeoPoint;
import org.mapsforge.core.MapPosition;
import org.mapsforge.database.FileOpenResult;
import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.MapFileInfo;
import org.mapsforge.database.mapfile.MapDatabase;
import org.xml.sax.SAXException;
import android.content.Context;
import android.opengl.GLSurfaceView;
@ -49,8 +59,7 @@ import android.view.MotionEvent;
* <p>
* This implementation supports offline map rendering as well as downloading map images (tiles) over an Internet
* connection. The operation mode of a MapView can be set in the constructor and changed at runtime with the
* {@link #setMapGeneratorInternal(IMapGenerator)} method. Some MapView parameters depend on the selected operation
* mode.
* {@link #setMapDatabase(MapDatabases)} method. Some MapView parameters depend on the selected operation mode.
* <p>
* In offline rendering mode a special database file is required which contains the map data. Map files can be stored in
* any folder. The current map file is set by calling {@link #setMapFile(String)}. To retrieve the current
@ -67,12 +76,12 @@ public class MapView extends GLSurfaceView {
public static final InternalRenderTheme DEFAULT_RENDER_THEME = InternalRenderTheme.OSMARENDER;
private static final float DEFAULT_TEXT_SCALE = 1;
private static final Byte DEFAULT_START_ZOOM_LEVEL = Byte.valueOf((byte) 16);
private final MapController mMapController;
// private final MapMover mMapMover;
// private final ZoomAnimator mZoomAnimator;
private final MapScaleBar mMapScaleBar;
// private final MapScaleBar mMapScaleBar;
private final MapViewPosition mMapViewPosition;
private final MapZoomControls mMapZoomControls;
@ -80,10 +89,11 @@ public class MapView extends GLSurfaceView {
private final TouchHandler mTouchEventHandler;
private IMapDatabase mMapDatabase;
private IMapGenerator mMapGenerator;
private MapRenderer mMapRenderer;
private MapDatabases mMapDatabaseType;
private IMapRenderer mMapRenderer;
private JobQueue mJobQueue;
private MapWorker mMapWorker;
private MapWorker mMapWorkers[];
private int mNumMapWorkers = 6;
private JobParameters mJobParameters;
private DebugSettings mDebugSettings;
private String mMapFile;
@ -95,9 +105,7 @@ public class MapView extends GLSurfaceView {
* if the context object is not an instance of {@link MapActivity} .
*/
public MapView(Context context) {
this(context, null,
MapGeneratorFactory.createMapGenerator(MapGeneratorInternal.GL_RENDERER),
MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.MAP_READER));
this(context, null, MapRenderers.GL_RENDERER, MapDatabases.MAP_READER);
}
/**
@ -110,25 +118,12 @@ public class MapView extends GLSurfaceView {
*/
public MapView(Context context, AttributeSet attributeSet) {
this(context, attributeSet,
MapGeneratorFactory.createMapGenerator(attributeSet),
MapDatabaseFactory.createMapDatabase(attributeSet));
}
/**
* @param context
* the enclosing MapActivity instance.
* @param mapGenerator
* the MapGenerator for this MapView.
* @throws IllegalArgumentException
* if the context object is not an instance of {@link MapActivity} .
*/
public MapView(Context context, IMapGenerator mapGenerator) {
this(context, null, mapGenerator, MapDatabaseFactory
.createMapDatabase(MapDatabaseInternal.MAP_READER));
MapRendererFactory.getMapGenerator(attributeSet),
MapDatabaseFactory.getMapDatabase(attributeSet));
}
private MapView(Context context, AttributeSet attributeSet,
IMapGenerator mapGenerator, IMapDatabase mapDatabase) {
MapRenderers mapGeneratorType, MapDatabases mapDatabaseType) {
super(context, attributeSet);
@ -147,46 +142,63 @@ public class MapView extends GLSurfaceView {
mJobParameters = new JobParameters(DEFAULT_RENDER_THEME, DEFAULT_TEXT_SCALE);
mMapController = new MapController(this);
// mMapDatabase = MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.POSTGIS_READER);
// mMapDatabase = MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.JSON_READER);
mMapDatabase = mapDatabase;
mMapDatabaseType = mapDatabaseType;
mMapViewPosition = new MapViewPosition(this);
mMapScaleBar = new MapScaleBar(this);
// mMapScaleBar = new MapScaleBar(this);
mMapZoomControls = new MapZoomControls(mapActivity, this);
mProjection = new MapViewProjection(this);
mTouchEventHandler = new TouchHandler(mapActivity, this);
mJobQueue = new JobQueue(this);
mMapWorker = new MapWorker(this);
mMapWorker.start();
// mMapMover = new MapMover(this);
// mMapMover.start();
// mZoomAnimator = new ZoomAnimator(this);
// mZoomAnimator.start();
setMapGeneratorInternal(mapGenerator);
mMapRenderer = MapRendererFactory.createMapRenderer(this, mapGeneratorType);
mMapWorkers = new MapWorker[mNumMapWorkers];
GeoPoint startPoint = mMapGenerator.getStartPoint();
if (startPoint != null) {
mMapViewPosition.setMapCenter(startPoint);
for (int i = 0; i < mNumMapWorkers; i++) {
IMapDatabase mapDatabase = MapDatabaseFactory
.createMapDatabase(mapDatabaseType);
IMapGenerator mapGenerator = mMapRenderer.createMapGenerator();
mapGenerator.setMapDatabase(mapDatabase);
if (i == 0) {
mMapDatabase = mapDatabase;
initMapStartPosition();
// mapGenerator.setRendertheme(DEFAULT_RENDER_THEME);
}
mMapWorkers[i] = new MapWorker(i, this, mapGenerator, mMapRenderer);
mMapWorkers[i].start();
}
Byte startZoomLevel = mMapGenerator.getStartZoomLevel();
if (startZoomLevel != null) {
mMapViewPosition.setZoomLevel(startZoomLevel.byteValue());
}
setRenderTheme(InternalRenderTheme.OSMARENDER);
mapActivity.registerMapView(this);
setEGLConfigChooser(new GlConfigChooser());
setEGLContextClientVersion(2);
mMapRenderer = mMapGenerator.getMapRenderer(this);
setRenderer(mMapRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
mMapWorker.setMapRenderer(mMapRenderer);
}
private void initMapStartPosition() {
GeoPoint startPoint = getStartPoint();
if (startPoint != null) {
mMapViewPosition.setMapCenter(startPoint);
}
Byte startZoomLevel = getStartZoomLevel();
if (startZoomLevel != null) {
mMapViewPosition.setZoomLevel(startZoomLevel.byteValue());
}
}
/**
@ -224,13 +236,6 @@ public class MapView extends GLSurfaceView {
return mMapFile;
}
/**
* @return the currently used MapGenerator (may be null).
*/
public IMapGenerator getMapGenerator() {
return mMapGenerator;
}
// /**
// * @return the MapMover which is used by this MapView.
// */
@ -245,19 +250,19 @@ public class MapView extends GLSurfaceView {
return mMapViewPosition;
}
/**
* @return the scale bar which is used in this MapView.
*/
public MapScaleBar getMapScaleBar() {
return mMapScaleBar;
}
// /**
// * @return the scale bar which is used in this MapView.
// */
// public MapScaleBar getMapScaleBar() {
// return mMapScaleBar;
// }
/**
* @return the zoom controls instance which is used in this MapView.
*/
public MapZoomControls getMapZoomControls() {
return mMapZoomControls;
}
// /**
// * @return the zoom controls instance which is used in this MapView.
// */
// public MapZoomControls getMapZoomControls() {
// return mMapZoomControls;
// }
/**
* @return the currently used projection of the map. Do not keep this object for a longer time.
@ -362,37 +367,41 @@ public class MapView extends GLSurfaceView {
// mZoomAnimator.pause();
// mMapMover.pause();
mMapWorker.pause();
// mZoomAnimator.awaitPausing();
// mMapMover.awaitPausing();
mMapWorker.awaitPausing();
// mZoomAnimator.proceed();
// mMapMover.stopMove();
// mMapMover.proceed();
mMapWorker.proceed();
mMapDatabase.closeFile();
boolean initialized = false;
if (mapFile != null)
fileOpenResult = mMapDatabase.openFile(new File(mapFile));
else
fileOpenResult = mMapDatabase.openFile(null);
mJobQueue.clear();
if (fileOpenResult != null && fileOpenResult.isSuccess()) {
mMapFile = mapFile;
mapWorkersPause();
GeoPoint startPoint = mMapGenerator.getStartPoint();
if (startPoint != null) {
Log.d(TAG, "mapfile got startpoint");
mMapViewPosition.setMapCenter(startPoint);
for (MapWorker mapWorker : mMapWorkers) {
IMapGenerator mapGenerator = mapWorker.getMapGenerator();
IMapDatabase mapDatabase = mapGenerator.getMapDatabase();
mapDatabase.closeFile();
if (mapFile != null)
fileOpenResult = mapDatabase.openFile(new File(mapFile));
else
fileOpenResult = mapDatabase.openFile(null);
if (fileOpenResult != null && fileOpenResult.isSuccess()) {
mMapFile = mapFile;
if (!initialized)
initialized = true;
}
}
Byte startZoomLevel = mMapGenerator.getStartZoomLevel();
if (startZoomLevel != null) {
Log.d(TAG, "mapfile got start zoomlevel");
mMapViewPosition.setZoomLevel(startZoomLevel.byteValue());
}
mapWorkersProceed();
if (initialized) {
clearAndRedrawMapView();
Log.d(TAG, "mapfile set");
return true;
@ -404,76 +413,61 @@ public class MapView extends GLSurfaceView {
return false;
}
/**
* Sets the MapGenerator for this MapView.
*
* @param mapGenerator
* the new MapGenerator.
*/
public void setMapGenerator(IMapGenerator mapGenerator) {
if (mMapGenerator != mapGenerator) {
setMapGeneratorInternal(mapGenerator);
clearAndRedrawMapView();
private GeoPoint getStartPoint() {
if (mMapDatabase != null && mMapDatabase.hasOpenFile()) {
MapFileInfo mapFileInfo = mMapDatabase.getMapFileInfo();
if (mapFileInfo.startPosition != null) {
return mapFileInfo.startPosition;
} else if (mapFileInfo.mapCenter != null) {
return mapFileInfo.mapCenter;
}
}
return null;
}
private void setMapGeneratorInternal(IMapGenerator mapGenerator) {
if (mapGenerator == null) {
throw new IllegalArgumentException("mapGenerator must not be null");
private Byte getStartZoomLevel() {
if (mMapDatabase != null && mMapDatabase.hasOpenFile()) {
MapFileInfo mapFileInfo = mMapDatabase.getMapFileInfo();
if (mapFileInfo.startZoomLevel != null) {
return mapFileInfo.startZoomLevel;
}
}
mapGenerator.setMapDatabase(mMapDatabase);
mMapGenerator = mapGenerator;
mMapWorker.setMapGenerator(mMapGenerator);
return DEFAULT_START_ZOOM_LEVEL;
}
/**
* Sets the MapDatabase for this MapView.
*
* @param mapDatabase
* @param mapDatabaseType
* the new MapDatabase.
*/
public void setMapDatabase(IMapDatabase mapDatabase) {
Log.d(TAG, "setMapDatabase " + mapDatabase.getClass());
if (mMapDatabase != mapDatabase) {
if (mMapDatabase != null)
mMapDatabase.closeFile();
public void setMapDatabase(MapDatabases mapDatabaseType) {
IMapGenerator mapGenerator;
setMapDatabaseInternal(mapDatabase);
Log.d(TAG, "setMapDatabase " + mapDatabaseType.name());
// clearAndRedrawMapView();
}
}
if (mMapDatabaseType == mapDatabaseType)
return;
private void setMapDatabaseInternal(IMapDatabase mapDatabase) {
if (mapDatabase == null) {
throw new IllegalArgumentException("MapDatabase must not be null");
}
mapWorkersPause();
if (!mMapWorker.isPausing()) {
mMapWorker.pause();
mMapWorker.awaitPausing();
for (MapWorker mapWorker : mMapWorkers) {
mapGenerator = mapWorker.getMapGenerator();
mapGenerator.setMapDatabase(MapDatabaseFactory
.createMapDatabase(mapDatabaseType));
}
mJobQueue.clear();
mMapDatabase = mapDatabase;
mMapGenerator.setMapDatabase(mMapDatabase);
Log.d(TAG, "setMapDatabaseInternal " + mapDatabase.getClass());
String mapFile = mMapFile;
mMapFile = null;
setMapFile(mapFile);
mMapWorker.proceed();
// mMapWorker.setMapDatabase(mMapDatabase);
mapWorkersProceed();
}
/**
@ -489,8 +483,7 @@ public class MapView extends GLSurfaceView {
throw new IllegalArgumentException("render theme must not be null");
}
Log.d(TAG, "set rendertheme " + internalRenderTheme);
mJobParameters = new JobParameters(internalRenderTheme, mJobParameters.textScale);
setRenderTheme((Theme) internalRenderTheme);
clearAndRedrawMapView();
}
@ -510,12 +503,40 @@ public class MapView extends GLSurfaceView {
throw new IllegalArgumentException("render theme path must not be null");
}
JobTheme jobTheme = new ExternalRenderTheme(renderThemePath);
mJobParameters = new JobParameters(jobTheme, mJobParameters.textScale);
setRenderTheme(new ExternalRenderTheme(renderThemePath));
clearAndRedrawMapView();
}
private boolean setRenderTheme(Theme theme) {
mapWorkersPause();
InputStream inputStream = null;
try {
inputStream = theme.getRenderThemeAsStream();
RenderTheme t = RenderThemeHandler.getRenderTheme(inputStream);
mMapWorkers[0].getMapGenerator().setRenderTheme(t);
return true;
} catch (ParserConfigurationException e) {
Log.e(TAG, e.getMessage());
} catch (SAXException e) {
Log.e(TAG, e.getMessage());
} catch (IOException e) {
Log.e(TAG, e.getMessage());
} finally {
mapWorkersProceed();
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
return false;
}
/**
* Sets the text scale for the map rendering. Has no effect in downloading mode.
*
@ -523,7 +544,7 @@ public class MapView extends GLSurfaceView {
* the new text scale for the map rendering.
*/
public void setTextScale(float textScale) {
mJobParameters = new JobParameters(mJobParameters.jobTheme, textScale);
mJobParameters = new JobParameters(mJobParameters.theme, textScale);
clearAndRedrawMapView();
}
@ -583,28 +604,33 @@ public class MapView extends GLSurfaceView {
@Override
protected synchronized void onSizeChanged(int width, int height, int oldWidth,
int oldHeight) {
mMapWorker.pause();
mMapWorker.awaitPausing();
super.onSizeChanged(width, height, oldWidth, oldHeight);
mMapWorker.proceed();
for (MapWorker mapWorker : mMapWorkers) {
mapWorker.pause();
mapWorker.awaitPausing();
super.onSizeChanged(width, height, oldWidth, oldHeight);
mapWorker.proceed();
}
// redrawTiles();
}
void destroy() {
// mMapMover.interrupt();
mMapWorker.interrupt();
// mZoomAnimator.interrupt();
try {
mMapWorker.join();
} catch (InterruptedException e) {
// restore the interrupted status
Thread.currentThread().interrupt();
for (MapWorker mapWorker : mMapWorkers) {
mapWorker.interrupt();
try {
mapWorker.join();
} catch (InterruptedException e) {
// restore the interrupted status
Thread.currentThread().interrupt();
}
IMapDatabase mapDatabase = mapWorker.getMapGenerator().getMapDatabase();
mapDatabase.closeFile();
}
mMapScaleBar.destroy();
mMapDatabase.closeFile();
// mMapScaleBar.destroy();
}
@ -612,8 +638,9 @@ public class MapView extends GLSurfaceView {
* @return the maximum possible zoom level.
*/
byte getMaximumPossibleZoomLevel() {
return (byte) Math.min(mMapZoomControls.getZoomLevelMax(),
mMapGenerator.getZoomLevelMax());
return (byte) 20;
// FIXME Math.min(mMapZoomControls.getZoomLevelMax(),
// mMapGenerator.getZoomLevelMax());
}
/**
@ -639,7 +666,9 @@ public class MapView extends GLSurfaceView {
@Override
public void onPause() {
super.onPause();
mMapWorker.pause();
for (MapWorker mapWorker : mMapWorkers)
mapWorker.pause();
// mMapMover.pause();
// mZoomAnimator.pause();
}
@ -647,7 +676,9 @@ public class MapView extends GLSurfaceView {
@Override
public void onResume() {
super.onResume();
mMapWorker.proceed();
for (MapWorker mapWorker : mMapWorkers)
mapWorker.proceed();
// mMapMover.proceed();
// mZoomAnimator.proceed();
}
@ -706,9 +737,33 @@ public class MapView extends GLSurfaceView {
}
/**
* @return MapWorker
* add jobs and remember MapWorkers that stuff needs to be done
*
* @param jobs
* tile jobs
*/
public MapWorker getMapWorker() {
return mMapWorker;
public void addJobs(ArrayList<MapGeneratorJob> jobs) {
mJobQueue.setJobs(jobs);
for (MapWorker m : mMapWorkers) {
synchronized (m) {
m.notify();
}
}
}
private void mapWorkersPause() {
for (MapWorker mapWorker : mMapWorkers) {
if (!mapWorker.isPausing()) {
mapWorker.pause();
mapWorker.awaitPausing();
}
}
}
private void mapWorkersProceed() {
for (MapWorker mapWorker : mMapWorkers)
mapWorker.proceed();
}
}

View File

@ -26,6 +26,7 @@ import android.util.FloatMath;
public class MapViewPosition {
private static float MAX_SCALE = 2.0f;
private static float MIN_SCALE = 1.0f;
private static int MAX_ZOOMLEVEL = 16;
private double mLatitude;
private double mLongitude;
@ -162,12 +163,14 @@ public class MapViewPosition {
float s = mScale * scale;
if (s >= MAX_SCALE) {
byte z = (byte) FloatMath.sqrt(s);
if (z != 0 && mZoomLevel == 20)
if (s > 8)
return;
mZoomLevel += z;
s *= 1.0f / (1 << z);
if (mZoomLevel <= MAX_ZOOMLEVEL) {
byte z = (byte) FloatMath.sqrt(s);
mZoomLevel += z;
s *= 1.0f / (1 << z);
}
} else if (s < MIN_SCALE) {
byte z = (byte) FloatMath.sqrt(1 / s);
if (z != 0 && mZoomLevel == 1)

View File

@ -18,31 +18,33 @@ package org.mapsforge.android.glrenderer;
import java.util.LinkedList;
class LayerPool {
static private LinkedList<PoolItem> pool;
static private LinkedList<PoolItem> pool = null;
static private int count;
static void init() {
pool = new LinkedList<PoolItem>();
count = 0;
if (pool == null) {
pool = new LinkedList<PoolItem>();
count = 0;
}
}
static PoolItem get() {
if (count == 0)
return new PoolItem();
PoolItem it;
synchronized (pool) {
count--;
it = pool.pop();
it.used = 0;
}
return it;
if (count == 0)
return new PoolItem();
count--;
PoolItem it = pool.pop();
it.used = 0;
return it;
}
}
static void add(LinkedList<PoolItem> items) {
int size = items.size();
synchronized (pool) {
int size = items.size();
while (count < 4096 && size-- > 0) {
count++;
pool.add(items.pop());

View File

@ -61,7 +61,7 @@ class LineLayers {
ByteOrder.nativeOrder());
fbuf = bbuf.asFloatBuffer();
} else {
fbuf.position(0);
fbuf.clear();
}
int pos = 0;
@ -81,7 +81,7 @@ class LineLayers {
l.pool = null;
}
fbuf.position(0);
fbuf.flip();
// not needed for drawing
layers = null;
@ -105,7 +105,7 @@ class LineLayers {
ByteOrder.nativeOrder());
sbuf = bbuf.asShortBuffer();
} else {
sbuf.position(0);
sbuf.clear();
}
int pos = 0;
@ -129,7 +129,7 @@ class LineLayers {
l.pool = null;
}
sbuf.position(0);
sbuf.flip();
// not needed for drawing
layers = null;

View File

@ -14,29 +14,19 @@
*/
package org.mapsforge.android.glrenderer;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import javax.xml.parsers.ParserConfigurationException;
import org.mapsforge.android.MapView;
import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.JobTheme;
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.rendertheme.IRenderCallback;
import org.mapsforge.android.rendertheme.RenderTheme;
import org.mapsforge.android.rendertheme.RenderThemeHandler;
import org.mapsforge.android.rendertheme.renderinstruction.Area;
import org.mapsforge.android.rendertheme.renderinstruction.Line;
import org.mapsforge.core.GeoPoint;
import org.mapsforge.core.WebMercator;
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
import org.mapsforge.core.MercatorProjection;
import org.mapsforge.core.Tag;
import org.mapsforge.core.Tile;
import org.mapsforge.core.WebMercator;
import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.IMapDatabaseCallback;
import org.mapsforge.database.MapFileInfo;
import org.xml.sax.SAXException;
import android.graphics.Bitmap;
import android.graphics.Color;
@ -46,33 +36,26 @@ import android.util.Log;
/**
*
*/
public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
IMapDatabaseCallback {
private static String TAG = DatabaseRenderer.class.getName();
public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabaseCallback {
private static String TAG = MapGenerator.class.getName();
private static final byte ZOOM_MAX = 22;
private static final Byte DEFAULT_START_ZOOM_LEVEL = Byte.valueOf((byte) 16);
private static final double PI180 = (Math.PI / 180) / 1000000.0;
private static final double PIx4 = Math.PI * 4;
private static final double STROKE_INCREASE = Math.sqrt(2);
private static final byte STROKE_MIN_ZOOM_LEVEL = 12;
private static final byte LAYERS = 11;
private static final double f900913 = 20037508.342789244;
private static RenderTheme renderTheme;
private IMapDatabase mMapDatabase;
private JobTheme mPreviousJobTheme;
// private float mPreviousTextScale;
private byte mPreviousZoomLevel;
private GLMapTile mCurrentTile;
private float[] mWayNodes;
private int[] mWays;
private ArrayList<float[]> mCurrentLines;
private LineLayers mLineLayers;
private PolygonLayers mPolyLayers;
private MeshLayers mMeshLayers;
@ -81,14 +64,13 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
private int mLevels;
private boolean useSphericalMercator = false;
private float mStrokeScale = 1.0f;
/**
*
*/
public DatabaseRenderer() {
public MapGenerator() {
Log.d(TAG, "init DatabaseRenderer");
mCurrentLines = new ArrayList<float[]>();
LayerPool.init();
}
@ -107,7 +89,6 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
private boolean mProjected;
private boolean mProjectedResult;
private float mSimplify;
private static final double f900913 = 20037508.342789244;
private boolean projectToTile(boolean area) {
if (mProjected)
@ -136,6 +117,8 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
for (int pos = 0, outPos = 0, i = 0, m = mWays.length; i < m; i++) {
int len = mWays[i];
if (len == 0)
continue;
int cnt = 0;
float lat, lon, prevLon = 0, prevLat = 0;
@ -197,6 +180,8 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
private boolean firstMatch;
private boolean prevClosed;
private RenderInstruction[] mRenderInstructions = null;
@Override
public void renderWay(byte layer, Tag[] tags, float[] wayNodes, int[] wayLength,
boolean changed) {
@ -220,17 +205,20 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
mSimplify = 0;
}
mCurrentLines.clear();
mWayNodes = wayNodes;
mWays = wayLength;
if (!firstMatch && prevClosed == closed && !changed) {
DatabaseRenderer.renderTheme.matchWay(this, tags,
(byte) (mCurrentTile.zoomLevel + 0),
closed, false);
if (mRenderInstructions != null) {
for (int i = 0, n = mRenderInstructions.length; i < n; i++)
mRenderInstructions[i].renderWay(this, tags);
}
// MapGenerator.renderTheme.matchWay(this, tags,
// (byte) (mCurrentTile.zoomLevel + 0),
// closed, false);
} else {
prevClosed = closed;
DatabaseRenderer.renderTheme.matchWay(this, tags,
mRenderInstructions = MapGenerator.renderTheme.matchWay(this, tags,
(byte) (mCurrentTile.zoomLevel + 0),
closed, true);
}
@ -273,9 +261,6 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
@Override
public void renderWay(Line line) {
// if (prevClosed && !mProjected)
// return;
projectToTile(false);
LineLayer outlineLayer = null;
@ -284,11 +269,12 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
float w = line.strokeWidth;
if (!line.fixed)
w *= mStrokeScale / 1.5f;
if (!line.fixed) {
w *= mStrokeScale;
w *= mProjectionScaleFactor;
}
if (line.outline != -1) {
Line outline = DatabaseRenderer.renderTheme.getOutline(line.outline);
Line outline = MapGenerator.renderTheme.getOutline(line.outline);
if (outline != null) {
outlineLayer = mLineLayers.getLayer(mDrawingLayer + outline.level,
outline.color, true, false);
@ -363,33 +349,19 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
if (mMapDatabase == null)
return false;
useSphericalMercator = WebMercator.NAME.equals(mMapDatabase.getMapProjection());
mCurrentTile = (GLMapTile) mapGeneratorJob.tile;
mDebugDrawPolygons = !mapGeneratorJob.debugSettings.mDisablePolygons;
// FIXME still chance of concurrency with maprenderer updateVisibleList ?
if (mCurrentTile.isLoading || mCurrentTile.isDrawn)
return false;
mCurrentTile.isLoading = true;
JobTheme jobTheme = mapGeneratorJob.jobParameters.jobTheme;
mLevels = MapGenerator.renderTheme.getLevels();
if (jobTheme != mPreviousJobTheme) {
if (!setRenderTheme(jobTheme)) {
mPreviousJobTheme = null;
return false;
}
mPreviousJobTheme = jobTheme;
mPreviousZoomLevel = Byte.MIN_VALUE;
mLevels = DatabaseRenderer.renderTheme.getLevels();
}
byte zoomLevel = mCurrentTile.zoomLevel;
if (zoomLevel != mPreviousZoomLevel) {
setScaleStrokeWidth(zoomLevel);
mPreviousZoomLevel = zoomLevel;
}
setScaleStrokeWidth(mCurrentTile.zoomLevel);
mLineLayers = new LineLayers();
mPolyLayers = new PolygonLayers();
@ -399,81 +371,32 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
mCurrentTile.meshLayers = mMeshLayers;
firstMatch = true;
mMapDatabase.executeQuery(mCurrentTile, this);
// Log.d(TAG, "loaded " + mCurrentTile);
mProjectionScaleFactor = (float) (1.0 / Math.cos(MercatorProjection
.pixelYToLatitude(mCurrentTile.pixelY, mCurrentTile.zoomLevel)
* (Math.PI / 180))) / 1.5f;
mMapDatabase.executeQuery(mCurrentTile, this);
if (mapGeneratorJob.debugSettings.mDrawTileFrames) {
float[] coords = { 0, 0, 0, Tile.TILE_SIZE, Tile.TILE_SIZE, Tile.TILE_SIZE,
Tile.TILE_SIZE, 0, 0, 0 };
LineLayer ll = mLineLayers.getLayer(Integer.MAX_VALUE, Color.BLACK, false,
true);
ll.addLine(coords, 0, coords.length, 1.0f, false);
ll.addLine(coords, 0, coords.length, 2.0f, false);
}
mCurrentTile.newData = true;
return true;
}
@Override
public GeoPoint getStartPoint() {
useSphericalMercator = false;
if (mMapDatabase != null && mMapDatabase.hasOpenFile()) {
MapFileInfo mapFileInfo = mMapDatabase.getMapFileInfo();
if (WebMercator.NAME.equals(mapFileInfo.projectionName)) {
Log.d(TAG, "using Spherical Mercator");
useSphericalMercator = true;
}
if (mapFileInfo.startPosition != null) {
return mapFileInfo.startPosition;
} else if (mapFileInfo.mapCenter != null) {
return mapFileInfo.mapCenter;
}
}
return null;
}
@Override
public Byte getStartZoomLevel() {
return DEFAULT_START_ZOOM_LEVEL;
}
@Override
public byte getZoomLevelMax() {
return ZOOM_MAX;
}
private static boolean setRenderTheme(JobTheme jobTheme) {
InputStream inputStream = null;
try {
inputStream = jobTheme.getRenderThemeAsStream();
DatabaseRenderer.renderTheme = RenderThemeHandler.getRenderTheme(inputStream);
return true;
} catch (ParserConfigurationException e) {
Log.e(TAG, e.getMessage());
} catch (SAXException e) {
Log.e(TAG, e.getMessage());
} catch (IOException e) {
Log.e(TAG, e.getMessage());
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
return false;
}
private float mProjectionScaleFactor;
private static byte getValidLayer(byte layer) {
if (layer < 0) {
return 0;
/**
* return instances of MapRenderer
*/
} else if (layer >= LAYERS) {
return LAYERS - 1;
} else {
@ -481,9 +404,17 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
}
}
@Override
public MapRenderer getMapRenderer(MapView mapView) {
return new MapRenderer(mapView);
/**
* Sets the scale stroke factor for the given zoom level.
*
* @param zoomLevel
* the zoom level for which the scale stroke factor should be set.
*/
private void setScaleStrokeWidth(byte zoomLevel) {
int zoomLevelDiff = Math.max(zoomLevel - STROKE_MIN_ZOOM_LEVEL, 0);
mStrokeScale = (float) Math.pow(STROKE_INCREASE, zoomLevelDiff);
if (mStrokeScale < 1)
mStrokeScale = 1;
}
@Override
@ -491,19 +422,13 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
mMapDatabase = mapDatabase;
}
private static float mStrokeScale = 1.0f;
@Override
public IMapDatabase getMapDatabase() {
return mMapDatabase;
}
/**
* Sets the scale stroke factor for the given zoom level.
*
* @param zoomLevel
* the zoom level for which the scale stroke factor should be set.
*/
private static void setScaleStrokeWidth(byte zoomLevel) {
int zoomLevelDiff = Math.max(zoomLevel - STROKE_MIN_ZOOM_LEVEL, 0);
mStrokeScale = (float) Math.pow(STROKE_INCREASE, zoomLevelDiff);
if (mStrokeScale < 1)
mStrokeScale = 1;
// DatabaseRenderer.renderTheme.scaleStrokeWidth(mStrokeScale);
@Override
public void setRenderTheme(RenderTheme theme) {
MapGenerator.renderTheme = theme;
}
}

View File

@ -14,6 +14,57 @@
*/
package org.mapsforge.android.glrenderer;
import static android.opengl.GLES20.GL_ARRAY_BUFFER;
import static android.opengl.GLES20.GL_BLEND;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.GL_DEPTH_TEST;
import static android.opengl.GLES20.GL_DITHER;
import static android.opengl.GLES20.GL_DYNAMIC_DRAW;
import static android.opengl.GLES20.GL_EQUAL;
import static android.opengl.GLES20.GL_EXTENSIONS;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_INVERT;
import static android.opengl.GLES20.GL_NEVER;
import static android.opengl.GLES20.GL_ONE_MINUS_SRC_ALPHA;
import static android.opengl.GLES20.GL_SCISSOR_TEST;
import static android.opengl.GLES20.GL_SRC_ALPHA;
import static android.opengl.GLES20.GL_STENCIL_BUFFER_BIT;
import static android.opengl.GLES20.GL_STENCIL_TEST;
import static android.opengl.GLES20.GL_TRIANGLES;
import static android.opengl.GLES20.GL_TRIANGLE_FAN;
import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
import static android.opengl.GLES20.GL_ZERO;
import static android.opengl.GLES20.glBindBuffer;
import static android.opengl.GLES20.glBlendFunc;
import static android.opengl.GLES20.glBufferData;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glClearStencil;
import static android.opengl.GLES20.glColorMask;
import static android.opengl.GLES20.glDepthMask;
import static android.opengl.GLES20.glDisable;
import static android.opengl.GLES20.glDisableVertexAttribArray;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glEnable;
import static android.opengl.GLES20.glEnableVertexAttribArray;
import static android.opengl.GLES20.glFinish;
import static android.opengl.GLES20.glGenBuffers;
import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetString;
import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glScissor;
import static android.opengl.GLES20.glStencilFunc;
import static android.opengl.GLES20.glStencilMask;
import static android.opengl.GLES20.glStencilOp;
import static android.opengl.GLES20.glUniform1f;
import static android.opengl.GLES20.glUniform2f;
import static android.opengl.GLES20.glUniform4f;
import static android.opengl.GLES20.glUniform4fv;
import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.GLES20.glUseProgram;
import static android.opengl.GLES20.glVertexAttribPointer;
import static android.opengl.GLES20.glViewport;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
@ -25,10 +76,9 @@ import javax.microedition.khronos.opengles.GL10;
import org.mapsforge.android.DebugSettings;
import org.mapsforge.android.MapView;
import org.mapsforge.android.mapgenerator.JobParameters;
import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.JobParameters;
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.mapgenerator.MapWorker;
import org.mapsforge.android.mapgenerator.TileCacheKey;
import org.mapsforge.android.mapgenerator.TileDistanceSort;
import org.mapsforge.android.utils.GlConfigChooser;
@ -47,12 +97,15 @@ import android.util.Log;
* TODO - use proxy child/parent tile nearer to current tile (currently it is always parent first) - use stencil instead
* of scissor mask for rotation - draw up to two parents above current tile, maybe prefetch parent
*/
public class MapRenderer implements org.mapsforge.android.MapRenderer {
public class MapRenderer implements org.mapsforge.android.IMapRenderer {
private static final String TAG = "MapRenderer";
private static final int MB = 1024 * 1024;
private boolean mTriangulate = false;
private static int CACHE_TILES_MAX = 400;
private static int CACHE_TILES = CACHE_TILES_MAX;
private static final int LIMIT_BUFFERS = 32 * (1024 * 1024);
private static int LIMIT_BUFFERS = 20 * MB;
private static final int OES_HALF_FLOAT = 0x8D61;
private static final int FLOAT_BYTES = 4;
@ -64,8 +117,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
private static int STENCIL_BITS = 8;
private final MapView mMapView;
private final MapWorker mMapWorker;
private final ArrayList<MapGeneratorJob> mJobList;
private final ArrayList<VertexBufferObject> mVBOs;
private final TileCacheKey mTileCacheKey;
@ -88,9 +139,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
// current center tile
private long mTileX, mTileY;
private FloatBuffer floatBuffer = null;
// private ByteBuffer byteBuffer = null;
private ShortBuffer shortBuffer = null;
private FloatBuffer floatBuffer[];
private ShortBuffer shortBuffer[];
boolean useHalfFloat = false;
@ -147,7 +197,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
public MapRenderer(MapView mapView) {
Log.d(TAG, "init MapRenderer");
mMapView = mapView;
mMapWorker = mapView.getMapWorker();
mDebugSettings = mapView.getDebugSettings();
mVBOs = new ArrayList<VertexBufferObject>();
@ -316,7 +365,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
mJobList.clear();
mJobParameter = mMapView.getJobParameters();
IMapGenerator mapGenerator = mMapView.getMapGenerator();
int tiles = 0;
if (newTiles == null)
return false;
@ -376,19 +424,19 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
newTiles.tiles[tiles++] = tile;
if (!tile.isDrawn && !tile.newData && !tile.isLoading) {
MapGeneratorJob job = new MapGeneratorJob(tile, mapGenerator,
mJobParameter, mDebugSettings);
MapGeneratorJob job = new MapGeneratorJob(tile, mJobParameter,
mDebugSettings);
mJobList.add(job);
}
// prefetch parent
if (tile.parent != null && !tile.parent.isDrawn && !tile.parent.newData
&& !tile.parent.isLoading) {
MapGeneratorJob job = new MapGeneratorJob(tile.parent, mapGenerator,
mJobParameter, mDebugSettings);
if (!mJobList.contains(job))
mJobList.add(job);
}
// if (tile.parent != null && !tile.parent.isDrawn && !tile.parent.newData
// && !tile.parent.isLoading) {
// MapGeneratorJob job = new MapGeneratorJob(tile.parent, mJobParameter,
// mDebugSettings);
// if (!mJobList.contains(job))
// mJobList.add(job);
// }
}
}
@ -419,12 +467,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
limitCache(removes);
if (mJobList.size() > 0) {
mMapView.getJobQueue().setJobs(mJobList);
synchronized (mMapWorker) {
mMapWorker.notify();
}
}
if (mJobList.size() > 0)
mMapView.addJobs(mJobList);
return true;
}
@ -513,7 +557,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
@Override
public boolean passTile(MapGeneratorJob mapGeneratorJob) {
if (!timing)
if (!timing && mapGeneratorJob.tile.isVisible)
mMapView.requestRender();
return true;
}
@ -524,10 +568,10 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
boolean blend = false;
// draw to framebuffer
GLES20.glColorMask(true, true, true, true);
glColorMask(true, true, true, true);
// do not modify stencil buffer
GLES20.glStencilMask(0);
glStencilMask(0);
for (int c = 0; c < count; c++) {
PolygonLayer l = mFillPolys[c];
@ -541,26 +585,26 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
alpha = 1.0f;
if (!blend) {
GLES20.glEnable(GLES20.GL_BLEND);
glEnable(GL_BLEND);
blend = true;
}
} else if (blend) {
GLES20.glDisable(GLES20.GL_BLEND);
glDisable(GL_BLEND);
blend = false;
}
GLES20.glUniform4f(gPolygonColorHandle,
glUniform4f(gPolygonColorHandle,
l.colors[0], l.colors[1], l.colors[2], alpha);
// set stencil buffer mask used to draw this layer
GLES20.glStencilFunc(GLES20.GL_EQUAL, 0xff, 1 << c);
glStencilFunc(GL_EQUAL, 0xff, 1 << c);
// draw tile fill coordinates
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
if (blend)
GLES20.glDisable(GLES20.GL_BLEND);
glDisable(GL_BLEND);
}
private boolean drawPolygons(GLMapTile tile, int diff) {
@ -569,63 +613,68 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (tile.polygonLayers == null || tile.polygonLayers.array == null)
return true;
GLES20.glScissor(tile.sx, tile.sy, tile.sw, tile.sh);
glScissor(tile.sx, tile.sy, tile.sw, tile.sh);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.id);
if (mLastBoundVBO != tile.polygonVBO.id) {
mLastBoundVBO = tile.polygonVBO.id;
glBindBuffer(GL_ARRAY_BUFFER, tile.polygonVBO.id);
if (useHalfFloat) {
GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
OES_HALF_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET);
} else {
GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
GLES20.GL_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET);
if (useHalfFloat) {
glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
OES_HALF_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET);
} else {
glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
GL_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET);
}
// glBindBuffer(GL_ARRAY_BUFFER, 0);
}
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
setMatrix(tile, diff);
GLES20.glUniformMatrix4fv(gPolygonMatrixHandle, 1, false, mMVPMatrix, 0);
glUniformMatrix4fv(gPolygonMatrixHandle, 1, false, mMVPMatrix, 0);
boolean firstPass = true;
for (int i = 0, n = tile.polygonLayers.array.length; i < n; i++) {
PolygonLayer l = tile.polygonLayers.array[i];
if (cnt == 0) {
// disable drawing to framebuffer
GLES20.glColorMask(false, false, false, false);
// never pass the test, i.e. always apply first stencil op (sfail)
GLES20.glStencilFunc(GLES20.GL_NEVER, 0, 0xff);
if (firstPass)
firstPass = false;
else {
// clear stencilbuffer
GLES20.glStencilMask(0xFF);
GLES20.glClear(GLES20.GL_STENCIL_BUFFER_BIT);
// clear stencilbuffer (tile region)
// GLES20.glStencilOp(GLES20.GL_ZERO, GLES20.GL_ZERO, GLES20.GL_ZERO);
// GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
// stencil op for stencil method polygon drawing
GLES20.glStencilOp(GLES20.GL_INVERT, GLES20.GL_INVERT, GLES20.GL_INVERT);
}
// fade out polygon layers (set in RederTheme)
if (l.fadeLevel > 0 && l.fadeLevel > mDrawZ)
continue;
if (cnt == 0) {
// disable drawing to framebuffer
glColorMask(false, false, false, false);
// never pass the test, i.e. always apply first stencil op (sfail)
glStencilFunc(GL_NEVER, 0, 0xff);
if (firstPass)
firstPass = false;
else {
// eeek, nexus! - cant do old-school polygons
// glFinish();
// clear stencilbuffer
glStencilMask(0xFF);
// glClear(GL_STENCIL_BUFFER_BIT);
// clear stencilbuffer (tile region)
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
// stencil op for stencil method polygon drawing
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
}
mFillPolys[cnt] = l;
// set stencil mask to draw to
GLES20.glStencilMask(1 << cnt++);
glStencilMask(1 << cnt++);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, l.offset, l.verticesCnt);
glDrawArrays(GL_TRIANGLE_FAN, l.offset, l.verticesCnt);
// draw up to 8 layers into stencil buffer
if (cnt == STENCIL_BITS) {
@ -634,47 +683,54 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
}
}
if (cnt > 0)
if (cnt > 0) {
fillPolygons(cnt);
// eeek, nexus! - cant do old-school polygons
// glFinish();
}
return true;
}
private int mLastBoundVBO;
private boolean drawTriangles(GLMapTile tile, int diff) {
if (tile.meshLayers == null || tile.meshLayers.array == null)
return true;
GLES20.glScissor(tile.sx, tile.sy, tile.sw, tile.sh);
glScissor(tile.sx, tile.sy, tile.sw, tile.sh);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.id);
if (mLastBoundVBO != tile.polygonVBO.id) {
mLastBoundVBO = tile.polygonVBO.id;
glBindBuffer(GL_ARRAY_BUFFER, tile.polygonVBO.id);
if (useHalfFloat) {
GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
OES_HALF_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET);
} else {
GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
GLES20.GL_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET);
if (useHalfFloat) {
glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
OES_HALF_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET);
} else {
glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
GL_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET);
}
// glBindBuffer(GL_ARRAY_BUFFER, 0);
}
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
setMatrix(tile, diff);
GLES20.glUniformMatrix4fv(gPolygonMatrixHandle, 1, false, mMVPMatrix, 0);
glUniformMatrix4fv(gPolygonMatrixHandle, 1, false, mMVPMatrix, 0);
MeshLayer[] layers = tile.meshLayers.array;
for (int i = 0, n = layers.length; i < n; i++) {
MeshLayer l = layers[i];
GLES20.glUniform4fv(gPolygonColorHandle, 1, l.colors, 0);
glUniform4fv(gPolygonColorHandle, 1, l.colors, 0);
// GLES20.glUniform4f(gPolygonColorHandle, 1, 0, 0, 1);
// glUniform4f(gPolygonColorHandle, 1, 0, 0, 1);
// System.out.println("draw: " + l.offset + " " + l.verticesCnt);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, l.offset, l.verticesCnt);
glDrawArrays(GL_TRIANGLES, l.offset, l.verticesCnt);
}
return true;
}
@ -684,30 +740,32 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (tile.lineLayers == null || tile.lineLayers.array == null)
return false;
GLES20.glScissor(tile.sx, tile.sy, tile.sw, tile.sh);
glScissor(tile.sx, tile.sy, tile.sw, tile.sh);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.id);
if (mLastBoundVBO != tile.lineVBO.id) {
mLastBoundVBO = tile.lineVBO.id;
glBindBuffer(GL_ARRAY_BUFFER, tile.lineVBO.id);
if (useHalfFloat) {
GLES20.glVertexAttribPointer(gLineVertexPositionHandle, 2, OES_HALF_FLOAT,
false, 8, LINE_VERTICES_DATA_POS_OFFSET);
if (useHalfFloat) {
glVertexAttribPointer(gLineVertexPositionHandle, 2, OES_HALF_FLOAT,
false, 8, LINE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(gLineTexturePositionHandle, 2, OES_HALF_FLOAT,
false, 8, LINE_VERTICES_DATA_TEX_OFFSET >> 1);
} else {
GLES20.glVertexAttribPointer(gLineVertexPositionHandle, 2, GLES20.GL_FLOAT,
false, 16, LINE_VERTICES_DATA_POS_OFFSET);
glVertexAttribPointer(gLineTexturePositionHandle, 2, OES_HALF_FLOAT,
false, 8, LINE_VERTICES_DATA_TEX_OFFSET >> 1);
} else {
glVertexAttribPointer(gLineVertexPositionHandle, 2, GL_FLOAT,
false, 16, LINE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(gLineTexturePositionHandle, 2, GLES20.GL_FLOAT,
false, 16, LINE_VERTICES_DATA_TEX_OFFSET);
glVertexAttribPointer(gLineTexturePositionHandle, 2, GL_FLOAT,
false, 16, LINE_VERTICES_DATA_TEX_OFFSET);
}
// glBindBuffer(GL_ARRAY_BUFFER, 0);
}
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
if (diff != 0)
z = (diff > 0) ? (1 << diff) : 1.0f / (1 << -diff);
setMatrix(tile, diff);
GLES20.glUniformMatrix4fv(gLineMatrixHandle, 1, false, mMVPMatrix, 0);
glUniformMatrix4fv(gLineMatrixHandle, 1, false, mMVPMatrix, 0);
LineLayer[] layers = tile.lineLayers.array;
@ -729,42 +787,37 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
drawFixed = l.isFixed;
if (drawOutlines) {
GLES20.glUniform2f(gLineModeHandle, 0, wdiv);
glUniform2f(gLineModeHandle, 0, wdiv);
} else if (!drawFixed) {
GLES20.glUniform2f(gLineModeHandle, 0, wdiv * 0.98f);
glUniform2f(gLineModeHandle, 0, wdiv * 0.98f);
}
}
if (drawFixed) {
if (l.width < 1.0)
GLES20.glUniform2f(gLineModeHandle, 0.4f, fdiv);
glUniform2f(gLineModeHandle, 0.4f, fdiv);
else
GLES20.glUniform2f(gLineModeHandle, 0, fdiv);
glUniform2f(gLineModeHandle, 0, fdiv);
}
GLES20.glUniform4fv(gLineColorHandle, 1, l.colors, 0);
glUniform4fv(gLineColorHandle, 1, l.colors, 0);
if (drawOutlines) {
for (int j = 0, m = l.outlines.size(); j < m; j++) {
LineLayer o = l.outlines.get(j);
if (mSimpleLines)
GLES20.glUniform1f(gLineWidthHandle, o.width);
glUniform1f(gLineWidthHandle, o.width);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, o.offset, o.verticesCnt);
glDrawArrays(GL_TRIANGLE_STRIP, o.offset, o.verticesCnt);
}
}
else {
if (mSimpleLines)
GLES20.glUniform1f(gLineWidthHandle, l.width);
glUniform1f(gLineWidthHandle, l.width);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, l.offset, l.verticesCnt);
glDrawArrays(GL_TRIANGLE_STRIP, l.offset, l.verticesCnt);
}
// cnt += l.verticesCnt;
}
// GLES20.glUniform2f(gLineModeHandle, 0, wdiv);
// float[] c = { 1, 0, 0, 1 };
// GLES20.glUniform4fv(gLineColorHandle, 1, c, 0);
// GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, cnt);
return true;
}
@ -940,47 +993,53 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
}
}
private boolean mTriangulate = false;
private int uploadCnt = 0;
private boolean uploadTileData(GLMapTile tile) {
// not sure about this, but seems it fixes some flickering when
// multiple tiles are uploaded in one go. but if this is really
// the issue tiles should stay corrupted..
if (uploadCnt++ > 0)
GLES20.glFinish();
// double start = SystemClock.uptimeMillis();
// use multiple buffers to avoid overwriting buffer while current data is uploaded
// (or rather the blocking which is required to avoid this)
if (uploadCnt >= 10) {
// mMapView.requestRender();
// return false;
uploadCnt = 0;
glFinish();
}
// Upload line data to vertex buffer object
if (tile.lineVBO == null) {
// Upload line data to vertex buffer object
synchronized (mVBOs) {
if (mVBOs.size() < 2)
if (mVBOs.size() < 2) {
Log.d(TAG, "uploadTileData, no VBOs left");
return false;
}
tile.lineVBO = mVBOs.remove(mVBOs.size() - 1);
tile.polygonVBO = mVBOs.remove(mVBOs.size() - 1);
}
}
if (useHalfFloat)
shortBuffer = tile.lineLayers.compileLayerData(shortBuffer);
shortBuffer[uploadCnt * 2] = tile.lineLayers
.compileLayerData(shortBuffer[uploadCnt * 2]);
else
floatBuffer = tile.lineLayers.compileLayerData(floatBuffer);
floatBuffer[uploadCnt * 2] = tile.lineLayers
.compileLayerData(floatBuffer[uploadCnt * 2]);
if (tile.lineLayers.size > 0) {
mBufferMemoryUsage -= tile.lineVBO.size;
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.id);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 0, null, GLES20.GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, tile.lineVBO.id);
// glBufferData(GL_ARRAY_BUFFER, 0, null, GL_DYNAMIC_DRAW);
if (useHalfFloat) {
tile.lineVBO.size = tile.lineLayers.size * SHORT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.size,
shortBuffer, GLES20.GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, tile.lineVBO.size,
shortBuffer[uploadCnt * 2], GL_DYNAMIC_DRAW);
} else {
tile.lineVBO.size = tile.lineLayers.size * FLOAT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.size,
floatBuffer, GLES20.GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, tile.lineVBO.size,
floatBuffer[uploadCnt * 2], GL_DYNAMIC_DRAW);
}
mBufferMemoryUsage += tile.lineVBO.size;
@ -991,26 +1050,28 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (!mTriangulate) {
if (useHalfFloat)
shortBuffer = tile.polygonLayers.compileLayerData(shortBuffer);
shortBuffer[uploadCnt * 2 + 1] = tile.polygonLayers
.compileLayerData(shortBuffer[uploadCnt * 2 + 1]);
else
floatBuffer = tile.polygonLayers.compileLayerData(floatBuffer);
floatBuffer[uploadCnt * 2 + 1] = tile.polygonLayers
.compileLayerData(floatBuffer[uploadCnt * 2 + 1]);
// Upload polygon data to vertex buffer object
if (tile.polygonLayers.size > 0) {
mBufferMemoryUsage -= tile.polygonVBO.size;
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.id);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 0, null,
GLES20.GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, tile.polygonVBO.id);
// glBufferData(GL_ARRAY_BUFFER, 0, null,
// GL_DYNAMIC_DRAW);
if (useHalfFloat) {
tile.polygonVBO.size = tile.polygonLayers.size * SHORT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size,
shortBuffer, GLES20.GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, tile.polygonVBO.size,
shortBuffer[uploadCnt * 2 + 1], GL_DYNAMIC_DRAW);
} else {
tile.polygonVBO.size = tile.polygonLayers.size * FLOAT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size,
floatBuffer, GLES20.GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, tile.polygonVBO.size,
floatBuffer[uploadCnt * 2 + 1], GL_DYNAMIC_DRAW);
}
mBufferMemoryUsage += tile.polygonVBO.size;
@ -1020,26 +1081,28 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
}
else {
if (useHalfFloat)
shortBuffer = tile.meshLayers.compileLayerData(shortBuffer);
shortBuffer[uploadCnt * 2 + 1] = tile.meshLayers
.compileLayerData(shortBuffer[uploadCnt * 2 + 1]);
else
floatBuffer = tile.meshLayers.compileLayerData(floatBuffer);
floatBuffer[uploadCnt * 2 + 1] = tile.meshLayers
.compileLayerData(floatBuffer[uploadCnt * 2 + 1]);
// Upload triangle data to vertex buffer object
if (tile.meshLayers.size > 0) {
mBufferMemoryUsage -= tile.polygonVBO.size;
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.id);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 0, null,
GLES20.GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, tile.polygonVBO.id);
// glBufferData(GL_ARRAY_BUFFER, 0, null,
// GL_DYNAMIC_DRAW);
if (useHalfFloat) {
tile.polygonVBO.size = tile.meshLayers.size * SHORT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size,
shortBuffer, GLES20.GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, tile.polygonVBO.size,
shortBuffer[uploadCnt * 2 + 1], GL_DYNAMIC_DRAW);
} else {
tile.polygonVBO.size = tile.meshLayers.size * FLOAT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size,
floatBuffer, GLES20.GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, tile.polygonVBO.size,
floatBuffer[uploadCnt * 2 + 1], GL_DYNAMIC_DRAW);
}
mBufferMemoryUsage += tile.polygonVBO.size;
@ -1050,6 +1113,13 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
tile.newData = false;
tile.isDrawn = true;
tile.isLoading = false;
// double compile = SystemClock.uptimeMillis();
// glFinish();
// double now = SystemClock.uptimeMillis();
// Log.d(TAG, tile + " - upload took: " + (now - start) + " "
// + (mBufferMemoryUsage / 1024) + "kb");
uploadCnt++;
return true;
}
@ -1066,10 +1136,9 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (timing)
start = SystemClock.uptimeMillis();
GLES20.glStencilMask(0xFF);
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT);
// GLES20.glFlush();
glStencilMask(0xFF);
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// long endTime = SystemClock.uptimeMillis();
// long dt = endTime - startTime;
@ -1100,22 +1169,21 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
GLMapTile[] tiles = curTiles.tiles;
if (mBufferMemoryUsage > LIMIT_BUFFERS) {
Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / (1024 * 1024)
+ "MB");
Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / MB + "MB");
synchronized (mVBOs) {
for (VertexBufferObject vbo : mVBOs) {
if (vbo.size == 0)
continue;
mBufferMemoryUsage -= vbo.size;
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo.id);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 0, null,
GLES20.GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
glBufferData(GL_ARRAY_BUFFER, 0, null,
GL_DYNAMIC_DRAW);
vbo.size = 0;
}
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
Log.d(TAG, " > " + mBufferMemoryUsage / (1024 * 1024) + "MB");
Log.d(TAG, " > " + mBufferMemoryUsage / MB + "MB");
if (CACHE_TILES > 50)
CACHE_TILES -= 50;
@ -1124,6 +1192,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
}
uploadCnt = 0;
mLastBoundVBO = -1;
// check visible tiles, set tile clip scissors, upload new vertex data
for (int i = 0; i < tileCnt; i++) {
@ -1134,11 +1203,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (tile.newData) {
uploadTileData(tile);
if (timing)
Log.d(TAG, "buffer upload took: "
+ (SystemClock.uptimeMillis() - start));
continue;
}
@ -1158,23 +1222,25 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
}
}
}
// GLES20.glFinish();
GlUtils.checkGlError("upload");
if (GlUtils.checkGlOutOfMemory("upload: " + mBufferMemoryUsage)
&& LIMIT_BUFFERS > MB)
LIMIT_BUFFERS -= MB;
if (timing)
clear_time = (SystemClock.uptimeMillis() - start);
GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
glEnable(GL_SCISSOR_TEST);
GLES20.glUseProgram(gPolygonProgram);
// GLES20.glEnableVertexAttribArray(gPolygonVertexPositionHandle);
glUseProgram(gPolygonProgram);
glEnableVertexAttribArray(gPolygonVertexPositionHandle);
if (!mTriangulate) {
GLES20.glDisable(GLES20.GL_BLEND);
glDisable(GL_BLEND);
// Draw Polygons
GLES20.glEnable(GLES20.GL_STENCIL_TEST);
glEnable(GL_STENCIL_TEST);
// GLES20.glEnableVertexAttribArray(gPolygonVertexPositionHandle);
// glEnableVertexAttribArray(gPolygonVertexPositionHandle);
for (int i = 0; i < tileCnt; i++) {
if (tiles[i].isVisible) {
@ -1186,8 +1252,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
drawProxyPolygons(tile);
}
}
GlUtils.checkGlError("polygons");
GLES20.glDisable(GLES20.GL_STENCIL_TEST);
// GlUtils.checkGlError("polygons");
glDisable(GL_STENCIL_TEST);
} else {
// Draw Triangles
for (int i = 0; i < tileCnt; i++) {
@ -1200,23 +1266,22 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
drawProxyTriangles(tile);
}
}
GlUtils.checkGlError("triangles");
// GlUtils.checkGlError("triangles");
}
// required on GalaxyII, Android 2.3.3
// GLES20.glDisableVertexAttribArray(gPolygonVertexPositionHandle);
// required on GalaxyII, Android 2.3.3 (cant just VAA enable once...)
glDisableVertexAttribArray(gPolygonVertexPositionHandle);
if (timing) {
GLES20.glFinish();
glFinish();
poly_time = (SystemClock.uptimeMillis() - start);
}
GLES20.glFlush();
// Draw lines
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glUseProgram(gLineProgram);
glEnable(GL_BLEND);
glUseProgram(gLineProgram);
// GLES20.glEnableVertexAttribArray(gLineVertexPositionHandle);
// GLES20.glEnableVertexAttribArray(gLineTexturePositionHandle);
glEnableVertexAttribArray(gLineVertexPositionHandle);
glEnableVertexAttribArray(gLineTexturePositionHandle);
for (int i = 0; i < tileCnt; i++) {
if (tiles[i].isVisible) {
@ -1230,14 +1295,13 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
}
if (timing) {
GLES20.glFinish();
glFinish();
Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start) + " "
+ clear_time + " " + poly_time);
}
// GLES20.glDisableVertexAttribArray(gLineVertexPositionHandle);
// GLES20.glDisableVertexAttribArray(gLineTexturePositionHandle);
GlUtils.checkGlError("lines");
GLES20.glFinish();
glDisableVertexAttribArray(gLineVertexPositionHandle);
glDisableVertexAttribArray(gLineTexturePositionHandle);
// GlUtils.checkGlError("lines");
}
private int[] mVboIds;
@ -1261,7 +1325,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
mHeight = height;
mAspect = (float) height / width;
GLES20.glViewport(0, 0, width, height);
glViewport(0, 0, width, height);
int tiles = (mWidth / Tile.TILE_SIZE + 4) * (mHeight / Tile.TILE_SIZE + 4);
curTiles = new TilesData(tiles);
@ -1271,7 +1335,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
// Set up vertex buffer objects
int numVBO = (CACHE_TILES + tiles) * 2;
mVboIds = new int[numVBO];
GLES20.glGenBuffers(numVBO, mVboIds, 0);
glGenBuffers(numVBO, mVboIds, 0);
for (int i = 0; i < numVBO; i++)
mVBOs.add(new VertexBufferObject(mVboIds[i]));
@ -1302,21 +1366,25 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
}
}
String ext = GLES20.glGetString(GLES20.GL_EXTENSIONS);
String ext = glGetString(GL_EXTENSIONS);
if (ext.indexOf("GL_OES_vertex_half_float") >= 0)
if (ext.indexOf("GL_OES_vertex_half_float") >= 0) {
useHalfFloat = true;
shortBuffer = new ShortBuffer[20];
}
else {
floatBuffer = new FloatBuffer[20];
}
Log.d(TAG, "Extensions: " + ext);
gLineMatrixHandle = GLES20.glGetUniformLocation(gLineProgram, "u_center");
gLineModeHandle = GLES20.glGetUniformLocation(gLineProgram, "u_mode");
gLineColorHandle = GLES20.glGetUniformLocation(gLineProgram, "u_color");
gLineMatrixHandle = glGetUniformLocation(gLineProgram, "u_center");
gLineModeHandle = glGetUniformLocation(gLineProgram, "u_mode");
gLineColorHandle = glGetUniformLocation(gLineProgram, "u_color");
gLineVertexPositionHandle = GLES20
.glGetAttribLocation(gLineProgram, "a_position");
gLineTexturePositionHandle = GLES20.glGetAttribLocation(gLineProgram, "a_st");
gLineTexturePositionHandle = glGetAttribLocation(gLineProgram, "a_st");
if (mSimpleLines)
gLineWidthHandle = GLES20.glGetUniformLocation(gLineProgram, "u_width");
gLineWidthHandle = glGetUniformLocation(gLineProgram, "u_width");
// Set up the program for rendering polygons
gPolygonProgram = GlUtils.createProgram(Shaders.gPolygonVertexShader,
@ -1325,31 +1393,39 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
Log.e(TAG, "Could not create polygon program.");
return;
}
gPolygonMatrixHandle = GLES20.glGetUniformLocation(gPolygonProgram, "u_center");
gPolygonVertexPositionHandle = GLES20.glGetAttribLocation(gPolygonProgram,
gPolygonMatrixHandle = glGetUniformLocation(gPolygonProgram, "u_center");
gPolygonVertexPositionHandle = glGetAttribLocation(gPolygonProgram,
"a_position");
gPolygonColorHandle = GLES20.glGetUniformLocation(gPolygonProgram, "u_color");
gPolygonColorHandle = glGetUniformLocation(gPolygonProgram, "u_color");
GLES20.glUseProgram(gPolygonProgram);
GLES20.glEnableVertexAttribArray(gPolygonVertexPositionHandle);
// glUseProgram(gPolygonProgram);
// glEnableVertexAttribArray(gPolygonVertexPositionHandle);
//
// glUseProgram(gLineProgram);
// glEnableVertexAttribArray(gLineVertexPositionHandle);
// glEnableVertexAttribArray(gLineTexturePositionHandle);
GLES20.glUseProgram(gLineProgram);
GLES20.glEnableVertexAttribArray(gLineVertexPositionHandle);
GLES20.glEnableVertexAttribArray(gLineTexturePositionHandle);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthMask(false);
GLES20.glDisable(GLES20.GL_DITHER);
GLES20.glClearColor(0.98f, 0.98f, 0.97f, 1.0f);
GLES20.glClearStencil(0);
// GLES20.glFrontFace(GLES20.GL_CCW);
glDisable(GL_DEPTH_TEST);
glDepthMask(false);
glDisable(GL_DITHER);
glClearColor(0.98f, 0.98f, 0.97f, 1.0f);
glClearStencil(0);
}
@Override
public boolean processedTile() {
return true;
}
public IMapGenerator getMapGenerator() {
return new MapGenerator();
}
@Override
public IMapGenerator createMapGenerator() {
return new MapGenerator();
}
}

View File

@ -75,7 +75,7 @@ class PolygonLayers {
// Log.d("GLMap", "allocate buffer " + size);
fbuf = bbuf.asFloatBuffer();
} else {
fbuf.position(0);
fbuf.clear();
}
fbuf.put(mFillCoords, 0, 8);
@ -95,7 +95,7 @@ class PolygonLayers {
l.pool = null;
}
fbuf.position(0);
fbuf.flip();
// not needed for drawing
layers = null;
@ -121,7 +121,7 @@ class PolygonLayers {
ByteOrder.nativeOrder());
sbuf = bbuf.asShortBuffer();
} else {
sbuf.position(0);
sbuf.clear();
}
short[] data = new short[PoolItem.SIZE];
@ -157,7 +157,7 @@ class PolygonLayers {
l.pool = null;
}
sbuf.position(0);
sbuf.flip();
// not needed for drawing
layers = null;

View File

@ -14,9 +14,7 @@
*/
package org.mapsforge.android.mapgenerator;
import org.mapsforge.android.MapRenderer;
import org.mapsforge.android.MapView;
import org.mapsforge.core.GeoPoint;
import org.mapsforge.android.rendertheme.RenderTheme;
import org.mapsforge.database.IMapDatabase;
/**
@ -37,31 +35,13 @@ public interface IMapGenerator {
*/
boolean executeJob(MapGeneratorJob mapGeneratorJob);
/**
* @return the start point of this MapGenerator (may be null).
*/
GeoPoint getStartPoint();
/**
* @return the start zoom level of this MapGenerator (may be null).
*/
Byte getStartZoomLevel();
/**
* @return the maximum zoom level that this MapGenerator supports.
*/
byte getZoomLevelMax();
/**
* @param mapView
* the MapView
* @return GLSurfaceView Renderer
*/
MapRenderer getMapRenderer(MapView mapView);
/**
* @param mapDatabase
* the MapDatabase from which the map data will be read.
*/
void setMapDatabase(IMapDatabase mapDatabase);
IMapDatabase getMapDatabase();
void setRenderTheme(RenderTheme theme);
}

View File

@ -22,7 +22,7 @@ public class JobParameters {
/**
* The render theme which should be used.
*/
public final JobTheme jobTheme;
public final Theme theme;
/**
* The text scale factor which should applied to the render theme.
@ -32,13 +32,13 @@ public class JobParameters {
private final int mHashCodeValue;
/**
* @param jobTheme
* @param theme
* render theme which should be used.
* @param textScale
* the text scale factor which should applied to the render theme.
*/
public JobParameters(JobTheme jobTheme, float textScale) {
this.jobTheme = jobTheme;
public JobParameters(Theme theme, float textScale) {
this.theme = theme;
this.textScale = textScale;
mHashCodeValue = calculateHashCode();
}
@ -52,11 +52,11 @@ public class JobParameters {
return false;
}
JobParameters other = (JobParameters) obj;
if (jobTheme == null) {
if (other.jobTheme != null) {
if (theme == null) {
if (other.theme != null) {
return false;
}
} else if (!jobTheme.equals(other.jobTheme)) {
} else if (!theme.equals(other.theme)) {
return false;
}
if (Float.floatToIntBits(textScale) != Float.floatToIntBits(other.textScale)) {
@ -75,7 +75,7 @@ public class JobParameters {
*/
private int calculateHashCode() {
int result = 7;
result = 31 * result + ((jobTheme == null) ? 0 : jobTheme.hashCode());
result = 31 * result + ((theme == null) ? 0 : theme.hashCode());
result = 31 * result + Float.floatToIntBits(textScale);
return result;
}

View File

@ -103,7 +103,8 @@ public class JobQueue {
* Schedules all jobs in this queue.
*/
private void schedule() {
PriorityQueue<MapGeneratorJob> tempJobQueue = new PriorityQueue<MapGeneratorJob>(INITIAL_CAPACITY);
PriorityQueue<MapGeneratorJob> tempJobQueue = new PriorityQueue<MapGeneratorJob>(
INITIAL_CAPACITY);
TileScheduler.time = SystemClock.uptimeMillis();
TileScheduler.mapPosition = mMapView.getMapPosition().getMapPosition();

View File

@ -37,29 +37,40 @@ public final class MapDatabaseFactory {
return new org.mapsforge.database.postgis.MapDatabase();
}
MapDatabaseInternal mapDatabaseInternal = MapDatabaseInternal
.valueOf(mapDatabaseName);
MapDatabases mapDatabaseInternal = MapDatabases.valueOf(mapDatabaseName);
return MapDatabaseFactory.createMapDatabase(mapDatabaseInternal);
}
public static MapDatabases getMapDatabase(AttributeSet attributeSet) {
String mapDatabaseName = attributeSet.getAttributeValue(null,
MAP_DATABASE_ATTRIBUTE_NAME);
if (mapDatabaseName == null) {
return MapDatabases.POSTGIS_READER;
}
return MapDatabases.valueOf(mapDatabaseName);
}
/**
* @param mapDatabaseInternal
* @param mapDatabase
* the internal MapDatabase implementation.
* @return a new MapGenerator instance.
*/
public static IMapDatabase createMapDatabase(MapDatabaseInternal mapDatabaseInternal) {
switch (mapDatabaseInternal) {
public static IMapDatabase createMapDatabase(MapDatabases mapDatabase) {
switch (mapDatabase) {
case MAP_READER:
return new org.mapsforge.database.mapfile.MapDatabase();
case JSON_READER:
return new org.mapsforge.database.json.MapDatabase();
case POSTGIS_READER:
return new org.mapsforge.database.postgis.MapDatabase();
case PBMAP_READER:
return new org.mapsforge.database.pbmap.MapDatabase();
}
throw new IllegalArgumentException("unknown enum value: " + mapDatabaseInternal);
throw new IllegalArgumentException("unknown enum value: " + mapDatabase);
}
private MapDatabaseFactory() {

View File

@ -17,7 +17,7 @@ package org.mapsforge.android.mapgenerator;
/**
* MapDatabase Implementations
*/
public enum MapDatabaseInternal {
public enum MapDatabases {
/**
* ...
*/
@ -33,4 +33,8 @@ public enum MapDatabaseInternal {
*/
POSTGIS_READER,
/**
* ...
*/
PBMAP_READER,
}

View File

@ -37,7 +37,7 @@ public class MapGeneratorJob implements Comparable<MapGeneratorJob>, Serializabl
/**
* The rendering parameters for this job.
*/
public final JobParameters jobParameters;
// public final JobParameters jobParameters;
/**
* The tile which should be generated.
@ -45,7 +45,6 @@ public class MapGeneratorJob implements Comparable<MapGeneratorJob>, Serializabl
public final MapTile tile;
private transient int mHashCodeValue;
private final IMapGenerator mMapGenerator;
private transient double mPriority;
/**
@ -90,18 +89,15 @@ public class MapGeneratorJob implements Comparable<MapGeneratorJob>, Serializabl
*
* @param _tile
* the tile which should be generated.
* @param mapGenerator
* the MapGenerator for this job.
* @param _jobParameters
* the rendering parameters for this job.
* @param _debugSettings
* the debug settings for this job.
*/
public MapGeneratorJob(MapTile _tile, IMapGenerator mapGenerator,
JobParameters _jobParameters, DebugSettings _debugSettings) {
public MapGeneratorJob(MapTile _tile, JobParameters _jobParameters,
DebugSettings _debugSettings) {
tile = _tile;
mMapGenerator = mapGenerator;
jobParameters = _jobParameters;
// jobParameters = _jobParameters;
debugSettings = _debugSettings;
calculateTransientValues();
}
@ -133,16 +129,14 @@ public class MapGeneratorJob implements Comparable<MapGeneratorJob>, Serializabl
} else if (!debugSettings.equals(other.debugSettings)) {
return false;
}
if (jobParameters == null) {
if (other.jobParameters != null) {
return false;
}
} else if (!jobParameters.equals(other.jobParameters)) {
return false;
}
if (mMapGenerator != other.mMapGenerator) {
return false;
}
// if (jobParameters == null) {
// if (other.jobParameters != null) {
// return false;
// }
// } else if (!jobParameters.equals(other.jobParameters)) {
// return false;
// }
if (tile == null) {
if (other.tile != null) {
return false;
@ -164,8 +158,7 @@ public class MapGeneratorJob implements Comparable<MapGeneratorJob>, Serializabl
private int calculateHashCode() {
int result = 1;
result = 31 * result + ((debugSettings == null) ? 0 : debugSettings.hashCode());
result = 31 * result + ((jobParameters == null) ? 0 : jobParameters.hashCode());
result = 31 * result + ((mMapGenerator == null) ? 0 : mMapGenerator.hashCode());
// result = 31 * result + ((jobParameters == null) ? 0 : jobParameters.hashCode());
result = 31 * result + ((tile == null) ? 0 : tile.hashCode());
return result;
}
@ -177,7 +170,8 @@ public class MapGeneratorJob implements Comparable<MapGeneratorJob>, Serializabl
mHashCodeValue = calculateHashCode();
}
private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
private void readObject(ObjectInputStream objectInputStream) throws IOException,
ClassNotFoundException {
objectInputStream.defaultReadObject();
calculateTransientValues();
}

View File

@ -14,46 +14,66 @@
*/
package org.mapsforge.android.mapgenerator;
import org.mapsforge.android.IMapRenderer;
import org.mapsforge.android.MapView;
import android.util.AttributeSet;
/**
* A factory for the internal MapGenerator implementations.
*/
public final class MapGeneratorFactory {
public final class MapRendererFactory {
private static final String MAP_GENERATOR_ATTRIBUTE_NAME = "mapGenerator";
/**
* @param mapView
* ...
* @param attributeSet
* A collection of attributes which includes the desired MapGenerator.
* @return a new MapGenerator instance.
*/
public static IMapGenerator createMapGenerator(AttributeSet attributeSet) {
String mapGeneratorName = attributeSet.getAttributeValue(null, MAP_GENERATOR_ATTRIBUTE_NAME);
public static IMapRenderer createMapRenderer(MapView mapView,
AttributeSet attributeSet) {
String mapGeneratorName = attributeSet.getAttributeValue(null,
MAP_GENERATOR_ATTRIBUTE_NAME);
if (mapGeneratorName == null) {
return new org.mapsforge.android.glrenderer.DatabaseRenderer();
return new org.mapsforge.android.glrenderer.MapRenderer(mapView);
}
MapGeneratorInternal mapGeneratorInternal = MapGeneratorInternal.valueOf(mapGeneratorName);
return MapGeneratorFactory.createMapGenerator(mapGeneratorInternal);
MapRenderers mapGeneratorInternal = MapRenderers.valueOf(mapGeneratorName);
return MapRendererFactory.createMapRenderer(mapView, mapGeneratorInternal);
}
public static MapRenderers getMapGenerator(AttributeSet attributeSet) {
String mapGeneratorName = attributeSet.getAttributeValue(null,
MAP_GENERATOR_ATTRIBUTE_NAME);
if (mapGeneratorName == null) {
return MapRenderers.GL_RENDERER;
}
return MapRenderers.valueOf(mapGeneratorName);
}
/**
* @param mapView
* ...
* @param mapGeneratorInternal
* the internal MapGenerator implementation.
* @return a new MapGenerator instance.
*/
public static IMapGenerator createMapGenerator(MapGeneratorInternal mapGeneratorInternal) {
public static IMapRenderer createMapRenderer(MapView mapView,
MapRenderers mapGeneratorInternal) {
switch (mapGeneratorInternal) {
case SW_RENDERER:
return new org.mapsforge.android.swrenderer.DatabaseRenderer();
return new org.mapsforge.android.swrenderer.MapRenderer(mapView);
case GL_RENDERER:
return new org.mapsforge.android.glrenderer.DatabaseRenderer();
return new org.mapsforge.android.glrenderer.MapRenderer(mapView);
}
throw new IllegalArgumentException("unknown enum value: " + mapGeneratorInternal);
}
private MapGeneratorFactory() {
private MapRendererFactory() {
throw new IllegalStateException();
}
}

View File

@ -17,7 +17,7 @@ package org.mapsforge.android.mapgenerator;
/**
* Enumeration of all internal MapGenerator implementations.
*/
public enum MapGeneratorInternal {
public enum MapRenderers {
/**
* texture renderer.
*/

View File

@ -14,7 +14,7 @@
*/
package org.mapsforge.android.mapgenerator;
import org.mapsforge.android.MapRenderer;
import org.mapsforge.android.IMapRenderer;
import org.mapsforge.android.MapView;
import org.mapsforge.android.utils.PausableThread;
@ -23,35 +23,33 @@ import org.mapsforge.android.utils.PausableThread;
* thread.
*/
public class MapWorker extends PausableThread {
private static final String THREAD_NAME = "MapWorker";
private final String THREAD_NAME;
private final JobQueue mJobQueue;
private IMapGenerator mMapGenerator;
private MapRenderer mMapRenderer;
private final IMapGenerator mMapGenerator;
private final IMapRenderer mMapRenderer;
/**
* @param id
* thread id
* @param mapView
* the MapView for which this MapWorker generates map tiles.
* @param mapGenerator
* ...
* @param mapRenderer
* ...
*/
public MapWorker(MapView mapView) {
public MapWorker(int id, MapView mapView, IMapGenerator mapGenerator,
IMapRenderer mapRenderer) {
super();
mJobQueue = mapView.getJobQueue();
}
/**
* @param mapGenerator
* the MapGenerator which this MapWorker should use.
*/
public void setMapGenerator(IMapGenerator mapGenerator) {
mMapGenerator = mapGenerator;
mMapRenderer = mapRenderer;
THREAD_NAME = "MapWorker" + id;
}
/**
* @param mapRenderer
* the MapRenderer
*/
public void setMapRenderer(MapRenderer mapRenderer) {
mMapRenderer = mapRenderer;
public IMapGenerator getMapGenerator() {
return mMapGenerator;
}
@Override
@ -65,6 +63,7 @@ public class MapWorker extends PausableThread {
if (mMapGenerator == null || mapGeneratorJob == null)
return;
// Log.d(THREAD_NAME, "processing: " + mapGeneratorJob.tile);
boolean success = mMapGenerator.executeJob(mapGeneratorJob);
@ -80,7 +79,8 @@ public class MapWorker extends PausableThread {
@Override
protected int getThreadPriority() {
return (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 2;
// return (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 2;
return Thread.MIN_PRIORITY;
}
@Override

View File

@ -21,7 +21,7 @@ import java.io.Serializable;
/**
* A JobTheme defines the render theme which is used for a {@link MapGeneratorJob}.
*/
public interface JobTheme extends Serializable {
public interface Theme extends Serializable {
/**
* @return an InputStream to read the render theme data from.
* @throws FileNotFoundException

View File

@ -21,12 +21,12 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import org.mapsforge.android.mapgenerator.JobTheme;
import org.mapsforge.android.mapgenerator.Theme;
/**
* An ExternalRenderTheme allows for customizing the rendering style of the map via an XML file.
*/
public class ExternalRenderTheme implements JobTheme {
public class ExternalRenderTheme implements Theme {
private static final long serialVersionUID = 1L;
private final long mFileModificationDate;

View File

@ -16,12 +16,12 @@ package org.mapsforge.android.rendertheme;
import java.io.InputStream;
import org.mapsforge.android.mapgenerator.JobTheme;
import org.mapsforge.android.mapgenerator.Theme;
/**
* Enumeration of all internal rendering themes.
*/
public enum InternalRenderTheme implements JobTheme {
public enum InternalRenderTheme implements Theme {
/**
* A rendering theme similar to the OpenStreetMap Osmarender style.
*
@ -37,6 +37,9 @@ public enum InternalRenderTheme implements JobTheme {
@Override
public InputStream getRenderThemeAsStream() {
return Thread.currentThread().getClass().getResourceAsStream(mPath);
// getResourceAsStream(mPath);
return InternalRenderTheme.class.getResourceAsStream(mPath);
// return Thread.currentThread().getClass().getResourceAsStream(mPath);
}
}

View File

@ -87,10 +87,6 @@ public class RenderTheme {
private final LRUCache<MatchingCacheKey, RenderInstruction[]> mMatchingCacheWay;
private final LRUCache<MatchingCacheKey, RenderInstruction[]> mMatchingCacheArea;
// private List<RenderInstruction> mMatchingListWay;
// private List<RenderInstruction> mMatchingListArea;
// private List<RenderInstruction> mMatchingListNode;
RenderTheme(int mapBackground, float baseStrokeWidth, float baseTextSize) {
mMapBackground = mapBackground;
mBaseStrokeWidth = baseStrokeWidth;
@ -198,7 +194,7 @@ public class RenderTheme {
}
}
private RenderInstruction[] mRenderInstructions = null;
// private RenderInstruction[] mRenderInstructions = null;
/**
* Matches a way with the given parameters against this RenderTheme.
@ -213,23 +209,26 @@ public class RenderTheme {
* way is Closed
* @param changed
* ...
* @return currently processed render instructions
*/
public void matchWay(IRenderCallback renderCallback, Tag[] tags, byte zoomLevel,
public synchronized RenderInstruction[] matchWay(IRenderCallback renderCallback,
Tag[] tags,
byte zoomLevel,
boolean closed, boolean changed) {
RenderInstruction[] renderInstructions = null;
LRUCache<MatchingCacheKey, RenderInstruction[]> matchingCache;
MatchingCacheKey matchingCacheKey;
if (!changed) {
renderInstructions = mRenderInstructions;
if (renderInstructions != null) {
for (int i = 0, n = renderInstructions.length; i < n; i++)
renderInstructions[i].renderWay(renderCallback, tags);
}
return;
}
// if (!changed) {
// renderInstructions = mRenderInstructions;
//
// if (renderInstructions != null) {
// for (int i = 0, n = renderInstructions.length; i < n; i++)
// renderInstructions[i].renderWay(renderCallback, tags);
// }
// return;
// }
if (closed) {
matchingCache = mMatchingCacheArea;
@ -267,90 +266,8 @@ public class RenderTheme {
matchingCache.put(matchingCacheKey, renderInstructions);
}
mRenderInstructions = renderInstructions;
// if (matchingList != null) {
// for (int i = 0, n = matchingList.size(); i < n; ++i) {
// matchingList.get(i).renderWay(renderCallback, tags);
// }
// }
// return renderInstructions;
// if (closed) {
// mMatchingListArea = matchingList;
// } else {
// mMatchingListWay = matchingList;
// }
// if (mCompareKey.set(tags, zoomLevel, closed)) {
// // Log.d("mapsforge", "SAME AS BAFORE!!!" + tags);
// for (int i = 0, n = mInstructionList.length; i < n; ++i) {
// mInstructionList[i].renderWay(renderCallback, tags);
// }
// return;
// }
//
// SparseArray<RenderInstruction[]> matchingList = mMatchingCache.get(mCompareKey);
//
// if (matchingList != null) {
// mInstructionList = matchingList.get(zoomLevel);
// if (mInstructionList != null) {
// // cache hit
// // Log.d("mapsforge", "CCACHE HIT !!!" + tags);
// for (int i = 0, n = mInstructionList.length; i < n; ++i) {
// mInstructionList[i].renderWay(renderCallback, tags);
// }
//
// return;
// }
// }
// // Log.d("mapsforge", "CACHE MISS !!!" + tags);
// // cache miss
// ArrayList<RenderInstruction> instructionList = new ArrayList<RenderInstruction>();
//
// for (int i = 0, n = mRulesList.size(); i < n; ++i) {
// mRulesList.get(i).matchWay(renderCallback, mCompareKey.getTags(), zoomLevel, closed, instructionList);
// }
//
// boolean found = false;
// int size = instructionList.size();
//
// if (matchingList == null) {
// matchingList = new SparseArray<RenderInstruction[]>(25);
// MatchingCacheKey matchingCacheKey = new MatchingCacheKey(mCompareKey);
// mMatchingCache.put(matchingCacheKey, matchingList);
// } else {
// // check if another zoomLevel uses the same instructionList
// for (int i = 0, n = matchingList.size(); i < n; i++) {
// int key = matchingList.keyAt(i);
//
// RenderInstruction[] list2 = matchingList.get(key);
// if (list2.length != size)
// continue;
//
// int j = 0;
// while (j < size && (list2[j] == instructionList.get(j)))
// j++;
//
// if (j == size) {
// instructionList.clear();
// mInstructionList = list2;
// found = true;
// break;
// }
// }
// }
//
// if (!found) {
// mInstructionList = new RenderInstruction[size];
// for (int i = 0; i < size; i++)
// mInstructionList[i] = instructionList.get(i);
// }
//
// for (int i = 0, n = mInstructionList.length; i < n; ++i)
// mInstructionList[i].renderWay(renderCallback, tags);
//
// matchingList.put(zoomLevel, mInstructionList);
// mRenderInstructions = renderInstructions;
return renderInstructions;
}
void addRule(Rule rule) {

File diff suppressed because it is too large Load Diff

View File

@ -14,77 +14,39 @@
*/
package org.mapsforge.android.swrenderer;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import org.mapsforge.android.MapView;
import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.JobTheme;
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.mapgenerator.Theme;
import org.mapsforge.android.rendertheme.IRenderCallback;
import org.mapsforge.android.rendertheme.RenderTheme;
import org.mapsforge.android.rendertheme.RenderThemeHandler;
import org.mapsforge.android.rendertheme.renderinstruction.Area;
import org.mapsforge.android.rendertheme.renderinstruction.Line;
import org.mapsforge.core.GeoPoint;
import org.mapsforge.core.Tag;
import org.mapsforge.core.Tile;
import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.IMapDatabaseCallback;
import org.mapsforge.database.MapFileInfo;
import org.mapsforge.database.mapfile.MapDatabase;
import org.xml.sax.SAXException;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.FloatMath;
import android.util.Log;
/**
* A DatabaseRenderer renders map tiles by reading from a {@link MapDatabase}.
*/
public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
public class MapGenerator implements IMapGenerator, IRenderCallback,
IMapDatabaseCallback {
private static String TAG = DatabaseRenderer.class.getName();
private static final Byte DEFAULT_START_ZOOM_LEVEL = Byte.valueOf((byte) 12);
// private static String TAG = MapGenerator.class.getName();
private static final byte LAYERS = 11;
private static final Paint PAINT_WATER_TILE_HIGHTLIGHT = new Paint(
Paint.ANTI_ALIAS_FLAG);
private static final double STROKE_INCREASE = 1.5;
private static final byte STROKE_MIN_ZOOM_LEVEL = 12;
private static final byte ZOOM_MAX = 22;
// private static MapRenderer mMapRenderer;
private static RenderTheme getRenderTheme(JobTheme jobTheme) {
InputStream inputStream = null;
try {
inputStream = jobTheme.getRenderThemeAsStream();
return RenderThemeHandler.getRenderTheme(inputStream);
} catch (ParserConfigurationException e) {
Log.e(TAG, e.getMessage());
} catch (SAXException e) {
Log.e(TAG, e.getMessage());
} catch (IOException e) {
Log.e(TAG, e.getMessage());
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
return null;
}
private static byte getValidLayer(byte layer) {
if (layer < 0) {
return 0;
@ -103,7 +65,7 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
private List<PointTextContainer> mNodes;
private float mPoiX;
private float mPoiY;
private JobTheme mPreviousJobTheme;
private Theme mPreviousJobTheme;
private float mPreviousTextScale;
private byte mPreviousZoomLevel;
private static RenderTheme renderTheme;
@ -138,7 +100,7 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
/**
* Constructs a new DatabaseRenderer.
*/
public DatabaseRenderer() {
public MapGenerator() {
mCanvasRasterer = new CanvasRasterer();
mLabelPlacement = new LabelPlacement();
@ -161,8 +123,8 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
@Override
public void cleanup() {
mTileBitmap.recycle();
if (DatabaseRenderer.renderTheme != null) {
DatabaseRenderer.renderTheme.destroy();
if (MapGenerator.renderTheme != null) {
MapGenerator.renderTheme.destroy();
}
}
@ -189,30 +151,30 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
// mTileHeight = mLat1 - mLat2;
mScale = mapGeneratorJob.getScale();
JobTheme jobTheme = mapGeneratorJob.jobParameters.jobTheme;
if (!jobTheme.equals(mPreviousJobTheme)) {
if (DatabaseRenderer.renderTheme == null)
DatabaseRenderer.renderTheme = getRenderTheme(jobTheme);
if (DatabaseRenderer.renderTheme == null) {
mPreviousJobTheme = null;
return false;
}
createWayLists();
mPreviousJobTheme = jobTheme;
mPreviousZoomLevel = Byte.MIN_VALUE;
}
byte zoomLevel = mCurrentTile.zoomLevel;
if (zoomLevel != mPreviousZoomLevel) {
setScaleStrokeWidth(zoomLevel);
mPreviousZoomLevel = zoomLevel;
}
float textScale = mapGeneratorJob.jobParameters.textScale;
if (textScale != mPreviousTextScale) {
DatabaseRenderer.renderTheme.scaleTextSize(textScale);
mPreviousTextScale = textScale;
}
// Theme theme = mapGeneratorJob.jobParameters.theme;
// if (!theme.equals(mPreviousJobTheme)) {
// // if (MapGenerator.renderTheme == null)
// // MapGenerator.renderTheme = getRenderTheme(theme);
// // if (MapGenerator.renderTheme == null) {
// // mPreviousJobTheme = null;
// // return false;
// // }
// createWayLists();
// mPreviousJobTheme = theme;
// mPreviousZoomLevel = Byte.MIN_VALUE;
// }
//
// byte zoomLevel = mCurrentTile.zoomLevel;
// if (zoomLevel != mPreviousZoomLevel) {
// setScaleStrokeWidth(zoomLevel);
// mPreviousZoomLevel = zoomLevel;
// }
//
// float textScale = mapGeneratorJob.jobParameters.textScale;
// if (textScale != mPreviousTextScale) {
// MapGenerator.renderTheme.scaleTextSize(textScale);
// mPreviousTextScale = textScale;
// }
if (mMapDatabase != null) {
mMapDatabase.executeQuery(mCurrentTile, this);
@ -230,7 +192,7 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
// FIXME mCoords = mMapDatabase.getCoordinates();
mCanvasRasterer.setCanvasBitmap(mTileBitmap, mScale);
mCanvasRasterer.fill(DatabaseRenderer.renderTheme.getMapBackground());
mCanvasRasterer.fill(MapGenerator.renderTheme.getMapBackground());
mCanvasRasterer.drawWays(mCoords, mWays);
mCanvasRasterer.drawSymbols(mWaySymbols);
mCanvasRasterer.drawSymbols(mPointSymbols);
@ -255,37 +217,6 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
return true;
}
@Override
public GeoPoint getStartPoint() {
if (mMapDatabase != null && mMapDatabase.hasOpenFile()) {
MapFileInfo mapFileInfo = mMapDatabase.getMapFileInfo();
if (mapFileInfo.startPosition != null) {
return mapFileInfo.startPosition;
} else if (mapFileInfo.mapCenter != null) {
return mapFileInfo.mapCenter;
}
}
return null;
}
@Override
public Byte getStartZoomLevel() {
if (mMapDatabase != null && mMapDatabase.hasOpenFile()) {
MapFileInfo mapFileInfo = mMapDatabase.getMapFileInfo();
if (mapFileInfo.startZoomLevel != null) {
return mapFileInfo.startZoomLevel;
}
}
return DEFAULT_START_ZOOM_LEVEL;
}
@Override
public byte getZoomLevelMax() {
return ZOOM_MAX;
}
@Override
public void renderAreaCaption(String textKey, float verticalOffset, Paint paint,
Paint stroke) {
@ -314,7 +245,7 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
mDrawingLayer = mWays[getValidLayer(layer)];
mPoiX = scaleLongitude(longitude);
mPoiY = scaleLatitude(latitude);
DatabaseRenderer.renderTheme.matchNode(this, tags, mCurrentTile.zoomLevel);
MapGenerator.renderTheme.matchNode(this, tags, mCurrentTile.zoomLevel);
}
@Override
@ -539,7 +470,7 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
}
private void createWayLists() {
int levels = DatabaseRenderer.renderTheme.getLevels();
int levels = MapGenerator.renderTheme.getLevels();
for (byte i = LAYERS - 1; i >= 0; --i) {
mWays[i] = new LayerContainer(levels);
}
@ -581,12 +512,18 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
*/
private static void setScaleStrokeWidth(byte zoomLevel) {
int zoomLevelDiff = Math.max(zoomLevel - STROKE_MIN_ZOOM_LEVEL, 0);
DatabaseRenderer.renderTheme.scaleStrokeWidth((float) Math.pow(STROKE_INCREASE,
MapGenerator.renderTheme.scaleStrokeWidth((float) Math.pow(STROKE_INCREASE,
zoomLevelDiff));
}
@Override
public MapRenderer getMapRenderer(MapView mapView) {
return new MapRenderer(mapView);
public IMapDatabase getMapDatabase() {
return mMapDatabase;
}
@Override
public void setRenderTheme(RenderTheme theme) {
// TODO Auto-generated method stub
}
}

View File

@ -28,10 +28,9 @@ import javax.microedition.khronos.opengles.GL10;
import org.mapsforge.android.DebugSettings;
import org.mapsforge.android.MapView;
import org.mapsforge.android.mapgenerator.JobParameters;
import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.JobParameters;
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.mapgenerator.MapWorker;
import org.mapsforge.android.mapgenerator.TileCacheKey;
import org.mapsforge.android.mapgenerator.TileDistanceSort;
import org.mapsforge.android.utils.GlUtils;
@ -46,7 +45,7 @@ import android.opengl.Matrix;
/**
*
*/
public class MapRenderer implements org.mapsforge.android.MapRenderer {
public class MapRenderer implements org.mapsforge.android.IMapRenderer {
// private static String TAG = "MapRenderer";
private static final int FLOAT_SIZE_BYTES = 4;
@ -72,7 +71,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
private ArrayList<MapGeneratorJob> mJobList;
ArrayList<Integer> mTextures;
MapWorker mMapWorker;
MapView mMapView;
GLMapTile[] currentTiles;
@ -97,7 +95,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
*/
public MapRenderer(MapView mapView) {
mMapView = mapView;
mMapWorker = mapView.getMapWorker();
mDebugSettings = mapView.getDebugSettings();
mMapScale = 1;
@ -133,7 +130,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (diff != 0)
{
float z = (diff > 0) ? (1 << diff) : 1.0f / (1 << -diff);
t.distance = (long) (Math.abs((t.tileX) * z - x) + Math.abs((t.tileY) * z - y));
t.distance = (long) (Math.abs((t.tileX) * z - x) + Math.abs((t.tileY) * z
- y));
t.distance *= 2 * diff * diff;
} else {
t.distance = (Math.abs(t.tileX - x) + Math.abs(t.tileY - y));
@ -160,7 +158,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
}
if (t.hasTexture()) {
synchronized (mTextures) {
mTextures.add(new Integer(t.getTexture()));
mTextures.add(Integer.valueOf(t.getTexture()));
}
}
}
@ -184,7 +182,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
mJobList.clear();
IMapGenerator mapGenerator = mMapView.getMapGenerator();
// IMapGenerator mapGenerator = mMapView.getMapGenerator();
int tiles = 0;
for (long tileY = tileTop - 1; tileY <= tileBottom + 1; tileY++) {
for (long tileX = tileLeft - 1; tileX <= tileRight + 1; tileX++) {
@ -216,13 +215,14 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (!tile.isDrawn || (tile.getScale() != scale)) {
tile.isLoading = true;
// approximation for TileScheduler
if (tileY < tileTop || tileY > tileBottom || tileX < tileLeft || tileX > tileRight)
if (tileY < tileTop || tileY > tileBottom || tileX < tileLeft
|| tileX > tileRight)
tile.isVisible = false;
else
tile.isVisible = true;
MapGeneratorJob job = new MapGeneratorJob(tile, mapGenerator,
mJobParameter, mDebugSettings);
MapGeneratorJob job = new MapGeneratorJob(tile, mJobParameter,
mDebugSettings);
job.setScale(scale);
mJobList.add(job);
}
@ -243,10 +243,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
}
if (mJobList.size() > 0) {
mMapView.getJobQueue().setJobs(mJobList);
synchronized (mMapWorker) {
mMapWorker.notify();
}
mMapView.addJobs(mJobList);
}
return true;
@ -262,10 +259,12 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
mMapPosition = mMapView.getMapPosition().getMapPosition();
long x = (long) MercatorProjection.longitudeToPixelX(mMapPosition.geoPoint.getLongitude(),
long x = (long) MercatorProjection.longitudeToPixelX(
mMapPosition.geoPoint.getLongitude(),
mMapPosition.zoomLevel);
long y = (long) MercatorProjection
.latitudeToPixelY(mMapPosition.geoPoint.getLatitude(), mMapPosition.zoomLevel);
.latitudeToPixelY(mMapPosition.geoPoint.getLatitude(),
mMapPosition.zoomLevel);
long tileX = MercatorProjection.pixelXToTileX(x, mMapPosition.zoomLevel);
long tileY = MercatorProjection.pixelYToTileY(y, mMapPosition.zoomLevel);
@ -345,7 +344,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
z = 1.0f / (1 << -diff);
}
drawX = MercatorProjection
.longitudeToPixelX(mMapPosition.geoPoint.getLongitude(), tile.zoomLevel);
.longitudeToPixelX(mMapPosition.geoPoint.getLongitude(),
tile.zoomLevel);
drawY = MercatorProjection
.latitudeToPixelY(mMapPosition.geoPoint.getLatitude(), tile.zoomLevel);
@ -377,7 +377,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
Matrix.setIdentityM(mMatrix, 0);
// map tile GL coordinates to screen coordinates
Matrix.scaleM(mMatrix, 0, 2.0f * (tileSize * z) / mWidth, 2.0f * (tileSize * z) / mHeight, 1);
Matrix.scaleM(mMatrix, 0, 2.0f * (tileSize * z) / mWidth, 2.0f * (tileSize * z)
/ mHeight, 1);
// scale tile
Matrix.scaleM(mMatrix, 0, mapScale / z, mapScale / z, 1);
@ -396,7 +397,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
@Override
public void onDrawFrame(GL10 glUnused) {
boolean loadedTexture = false;
// boolean loadedTexture = false;
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
GLES20.glClearColor(0.95f, 0.95f, 0.94f, 1.0f);
// GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
@ -437,14 +438,16 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (tile.getTexture() >= 0) {
// reuse tile texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tile.getTexture());
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mMapGeneratorJob.getBitmap());
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
mMapGeneratorJob.getBitmap());
} else if (mTextures.size() > 0) {
// reuse texture from previous tiles
Integer texture;
texture = mTextures.remove(mTextures.size() - 1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture.intValue());
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mMapGeneratorJob.getBitmap());
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0,
mMapGeneratorJob.getBitmap());
tile.setTexture(texture.intValue());
} else {
// create texture
@ -457,7 +460,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
mMapGeneratorJob = null;
processedTile = true;
loadedTexture = true;
// loadedTexture = true;
}
int tileSize = (int) (Tile.TILE_SIZE * mMapScale);
int hWidth = mWidth >> 1;
@ -491,11 +494,12 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
}
}
}
if (loadedTexture) {
synchronized (mMapWorker) {
mMapWorker.notify();
}
}
// FIXME
// if (loadedTexture) {
// synchronized (mMapWorker) {
// mMapWorker.notify();
// }
// }
}
@Override
@ -579,65 +583,9 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
public boolean processedTile() {
return processedTile;
}
@Override
public IMapGenerator createMapGenerator() {
return new MapGenerator();
}
}
// private void limitCache(long top, long bottom, long left, long right, byte zoom, int remove) {
// int cnt = 0;
// TileCacheKey[] keys = new TileCacheKey[remove];
//
// for (Entry<TileCacheKey, GLMapTile> e : mTiles.entrySet()) {
// GLMapTile t = e.getValue();
// if (t.zoomLevel == zoom && t.tileX >= left && t.tileX <= right &&
// t.tileY >= top && t.tileY <= bottom)
// continue;
//
// if (t.zoomLevel + 1 == zoom) {
// boolean found = false;
// for (int i = 0; i < 4; i++) {
// GLMapTile c = t.child[i];
// if (c != null && !c.hasTexture() && c.tileX >= left && c.tileX <= right &&
// c.tileY >= top && c.tileY <= bottom) {
// found = true;
// break;
// }
// }
// if (found)
// continue;
// }
// if (t.zoomLevel - 1 == zoom) {
// GLMapTile p = t.parent;
// if (p != null && !p.hasTexture() && p.tileX >= left && p.tileX <= right &&
// p.tileY >= top && p.tileY <= bottom) {
// continue;
// }
// }
//
// keys[cnt++] = e.getKey();
//
// if (cnt == remove)
// break;
// }
//
// for (TileCacheKey key : keys) {
// GLMapTile t = mTiles.remove(key);
// if (t == null)
// continue;
//
// for (int i = 0; i < 4; i++) {
// if (t.child[i] != null)
// t.child[i].parent = null;
// }
// if (t.parent != null) {
// for (int i = 0; i < 4; i++) {
// if (t.parent.child[i] == t)
// t.parent.child[i] = null;
// }
// }
// if (t.hasTexture()) {
// synchronized (mTextures) {
// mTextures.add(new Integer(t.getTexture()));
// }
// }
// }
// }

View File

@ -99,7 +99,7 @@ final class WayDecorator {
}
}
static void renderText(DatabaseRenderer databaseRenderer, Paint paint, Paint outline,
static void renderText(MapGenerator mapGenerator, Paint paint, Paint outline,
float[] coordinates, WayDataContainer wayDataContainer,
List<WayTextContainer> wayNames) {
@ -185,7 +185,7 @@ final class WayDecorator {
if (wayNameWidth < 0) {
if (text == null) {
text = databaseRenderer.getWayName();
text = mapGenerator.getWayName();
if (text == null)
text = "blub";
}

View File

@ -40,13 +40,17 @@ public class GlUtils {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
@ -125,4 +129,16 @@ public class GlUtils {
// throw new RuntimeException(op + ": glError " + error);
}
}
public static boolean checkGlOutOfMemory(String op) {
int error;
boolean oom = false;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e(TAG, op + ": glError " + error);
// throw new RuntimeException(op + ": glError " + error);
if (error == 1285)
oom = true;
}
return oom;
}
}

View File

@ -37,6 +37,14 @@ public abstract class PausableThread extends Thread {
}
}
@Override
public void interrupt() {
// first acquire the monitor which is used to call wait()
synchronized (this) {
super.interrupt();
}
}
/**
* @return true if this thread is currently pausing, false otherwise.
*/

View File

@ -9,8 +9,7 @@ import org.mapsforge.android.DebugSettings;
import org.mapsforge.android.MapActivity;
import org.mapsforge.android.MapController;
import org.mapsforge.android.MapView;
import org.mapsforge.android.mapgenerator.MapDatabaseFactory;
import org.mapsforge.android.mapgenerator.MapDatabaseInternal;
import org.mapsforge.android.mapgenerator.MapDatabases;
import org.mapsforge.android.rendertheme.InternalRenderTheme;
import org.mapsforge.android.utils.AndroidUtils;
import org.mapsforge.app.filefilter.FilterByFileExtension;
@ -20,7 +19,6 @@ import org.mapsforge.app.filepicker.FilePicker;
import org.mapsforge.app.preferences.EditPreferences;
import org.mapsforge.core.BoundingBox;
import org.mapsforge.core.GeoPoint;
import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.MapFileInfo;
import android.annotation.TargetApi;
@ -74,7 +72,7 @@ public class TileMap extends MapActivity { // implements ActionBar.OnNavigationL
private static final int SELECT_MAP_FILE = 0;
private static final int SELECT_RENDER_THEME_FILE = 1;
private LocationManager mLocationManager;
private MapDatabaseInternal mMapDatabaseInternal;
private MapDatabases mMapDatabase;
private MyLocationListener mMyLocationListener;
private boolean mShowMyLocation;
private boolean mSnapToLocation;
@ -88,8 +86,11 @@ public class TileMap extends MapActivity { // implements ActionBar.OnNavigationL
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.options_menu, menu);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
getMenuInflater().inflate(R.menu.options_menu, menu);
else
getMenuInflater().inflate(R.menu.options_menu_pre_honeycomb, menu);
mMenu = menu;
return true;
}
@ -434,7 +435,7 @@ public class TileMap extends MapActivity { // implements ActionBar.OnNavigationL
editText.setText(Double.toString(mapCenter.getLongitude()));
SeekBar zoomlevel = (SeekBar) dialog.findViewById(R.id.zoomLevel);
zoomlevel.setMax(mMapView.getMapGenerator().getZoomLevelMax());
zoomlevel.setMax(20); // FIXME mMapView.getMapGenerator().getZoomLevelMax());
zoomlevel.setProgress(mMapView.getMapPosition().getZoomLevel());
final TextView textView = (TextView) dialog.findViewById(R.id.zoomlevelValue);
@ -532,25 +533,31 @@ public class TileMap extends MapActivity { // implements ActionBar.OnNavigationL
if (preferences.contains("mapDatabase")) {
String name = preferences.getString("mapDatabase",
MapDatabaseInternal.POSTGIS_READER.name());
MapDatabases.POSTGIS_READER.name());
MapDatabaseInternal mapDatabaseInternalNew;
MapDatabases mapDatabaseNew;
try {
mapDatabaseInternalNew = MapDatabaseInternal.valueOf(name);
mapDatabaseNew = MapDatabases.valueOf(name);
} catch (IllegalArgumentException e) {
mapDatabaseInternalNew = MapDatabaseInternal.POSTGIS_READER;
mapDatabaseNew = MapDatabases.POSTGIS_READER;
}
// mapDatabaseInternalNew = MapDatabaseInternal.JSON_READER;
Log.d("VectorTileMap", "set map database " + mapDatabaseInternalNew);
// mapDatabaseInternalNew = MapDatabaseInternal.PBMAP_READER;
Log.d("VectorTileMap", "set map database " + mapDatabaseNew);
if (mapDatabaseInternalNew != mMapDatabaseInternal) {
IMapDatabase mapDatabase = MapDatabaseFactory
.createMapDatabase(mapDatabaseInternalNew);
mMapView.setMapDatabase(mapDatabase);
mMapDatabaseInternal = mapDatabaseInternalNew;
if (mapDatabaseNew != mMapDatabase) {
mMapView.setMapDatabase(mapDatabaseNew);
mMapDatabase = mapDatabaseNew;
}
// if (mapDatabaseNew != mMapDatabase) {
// IMapDatabase mapDatabase = MapDatabaseFactory
// .createMapDatabase(mapDatabaseNew);
//
// mMapView.setMapDatabase(mapDatabase);
// mMapDatabase = mapDatabaseNew;
// }
}
try {
@ -586,7 +593,7 @@ public class TileMap extends MapActivity { // implements ActionBar.OnNavigationL
mMapView.setDebugSettings(debugSettings);
if (mMapDatabaseInternal == MapDatabaseInternal.MAP_READER) {
if (mMapDatabase == MapDatabases.MAP_READER) {
if (mMapView.getMapFile() == null)
startMapFilePicker();
} else {

View File

@ -226,7 +226,8 @@ public class FilePicker extends Activity implements AdapterView.OnItemClickListe
@Override
protected void onResume() {
super.onResume();
getActionBar().hide();
// getActionBar().hide();
// check if the full screen mode should be activated
// if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("fullscreen", false)) {
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

View File

@ -18,8 +18,6 @@ import org.mapsforge.app.R;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.view.WindowManager;
/**
* Activity to edit the application preferences.
@ -34,16 +32,16 @@ public class EditPreferences extends PreferenceActivity {
@Override
protected void onResume() {
super.onResume();
getActionBar().hide();
// getActionBar().hide();
// check if the full screen mode should be activated
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("fullscreen",
false)) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
// if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("fullscreen",
// false)) {
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
// } else {
// getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
// }
}
}

View File

@ -62,6 +62,8 @@ public interface IMapDatabase {
*/
public abstract FileOpenResult openFile(File mapFile);
public abstract String getMapProjection();
/**
* @param position
* ....
@ -69,4 +71,4 @@ public interface IMapDatabase {
*/
public abstract String readString(int position);
}
}

View File

@ -31,13 +31,14 @@ import org.mapsforge.database.MapFileInfo;
*/
public class MapDatabase implements IMapDatabase {
private final static String PROJECTION = "Mercator";
private float[] mCoords = new float[20];
private int[] mIndex = new int[1];
private int[] mIndex = new int[2];
// private Tag[] mTags = { new Tag("boundary", "administrative"), new Tag("admin_level", "2") };
private Tag[] mTags = { new Tag("building", "yes") };
private Tag[] mTags = { new Tag("natural", "water") };
private final MapFileInfo mMapInfo =
new MapFileInfo(new BoundingBox(-180, -90, 180, 90),
new Byte((byte) 0), null, "Mercator", 0, 0, 0, "de", "yo!", "by me");
new Byte((byte) 0), null, PROJECTION, 0, 0, 0, "de", "yo!", "by me");
private boolean mOpenFile = false;
@ -95,10 +96,10 @@ public class MapDatabase implements IMapDatabase {
//
// mIndex[0] = 10;
lon1 = (float) MercatorProjection.pixelXToLongitude(cx - 80, tile.zoomLevel) * 1000000;
lon2 = (float) MercatorProjection.pixelXToLongitude(cx + 80, tile.zoomLevel) * 1000000;
lat1 = (float) MercatorProjection.pixelYToLatitude(cy - 80, tile.zoomLevel) * 1000000;
lat2 = (float) MercatorProjection.pixelYToLatitude(cy + 80, tile.zoomLevel) * 1000000;
lon1 = (float) MercatorProjection.pixelXToLongitude(cx - 139, tile.zoomLevel) * 1000000;
lon2 = (float) MercatorProjection.pixelXToLongitude(cx + 139, tile.zoomLevel) * 1000000;
lat1 = (float) MercatorProjection.pixelYToLatitude(cy - 139, tile.zoomLevel) * 1000000;
lat2 = (float) MercatorProjection.pixelYToLatitude(cy + 139, tile.zoomLevel) * 1000000;
mCoords[0] = lon1;
mCoords[1] = lat1;
@ -117,9 +118,35 @@ public class MapDatabase implements IMapDatabase {
mIndex[0] = 10;
lon1 = (float) MercatorProjection.pixelXToLongitude(cx - 119, tile.zoomLevel) * 1000000;
lon2 = (float) MercatorProjection.pixelXToLongitude(cx + 119, tile.zoomLevel) * 1000000;
lat1 = (float) MercatorProjection.pixelYToLatitude(cy - 119, tile.zoomLevel) * 1000000;
lat2 = (float) MercatorProjection.pixelYToLatitude(cy + 119, tile.zoomLevel) * 1000000;
mCoords[10] = lon1;
mCoords[11] = lat1;
mCoords[12] = lon2;
mCoords[13] = lat1;
mCoords[14] = lon2;
mCoords[15] = lat2;
mCoords[16] = lon1;
mCoords[17] = lat2;
mCoords[18] = lon1;
mCoords[19] = lat1;
mIndex[1] = 10;
mapDatabaseCallback.renderWay((byte) 0, mTags, mCoords, mIndex, true);
}
@Override
public String getMapProjection() {
return PROJECTION;
}
@Override
public MapFileInfo getMapFileInfo() {
return mMapInfo;

View File

@ -177,11 +177,13 @@ public class MapDatabase implements IMapDatabase {
*/
private static final int WAY_NUMBER_OF_TAGS_BITMASK = 0x0f;
private IndexCache mDatabaseIndexCache;
private static IndexCache sDatabaseIndexCache;
private static MapFileHeader sMapFileHeader;
private static int instances = 0;
private long mFileSize;
private boolean mDebugFile;
private RandomAccessFile mInputFile;
private MapFileHeader mMapFileHeader;
private ReadBuffer mReadBuffer;
private String mSignatureBlock;
private String mSignaturePoi;
@ -193,31 +195,6 @@ public class MapDatabase implements IMapDatabase {
private float[] mWayNodes = new float[100000];
private int mWayNodePosition;
/*
* (non-Javadoc)
* @see org.mapsforge.map.reader.IMapDatabase#closeFile()
*/
@Override
public void closeFile() {
try {
mMapFileHeader = null;
if (mDatabaseIndexCache != null) {
mDatabaseIndexCache.destroy();
mDatabaseIndexCache = null;
}
if (mInputFile != null) {
mInputFile.close();
mInputFile = null;
}
mReadBuffer = null;
} catch (IOException e) {
LOG.log(Level.SEVERE, null, e);
}
}
private int minLat, minLon;
/*
@ -227,7 +204,7 @@ public class MapDatabase implements IMapDatabase {
*/
@Override
public void executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) {
if (mMapFileHeader == null)
if (sMapFileHeader == null)
return;
if (mIntBuffer == null)
@ -235,29 +212,13 @@ public class MapDatabase implements IMapDatabase {
mWayNodePosition = 0;
// if (tile.zoomLevel < 10) {
// // reduce small nodes with distance smaller min pixel
// int min = 1;
// long cx = tile.getPixelX() + (Tile.TILE_SIZE >> 1);
// long cy = tile.getPixelY() + (Tile.TILE_SIZE >> 1);
// double l1 = MercatorProjection.pixelXToLongitude(cx, tile.zoomLevel);
// double l2 = MercatorProjection.pixelXToLongitude(cx + min, tile.zoomLevel);
// minLon = (int) Math.abs((l1 * 1000000.0) - (l2 * 1000000.0));
// l1 = MercatorProjection.pixelYToLatitude(cy, tile.zoomLevel);
// l2 = MercatorProjection.pixelYToLatitude(cy + min, tile.zoomLevel);
// minLat = (int) Math.abs((l1 * 1000000.0) - (l2 * 1000000.0));
// } else {
minLat = 0;
minLon = 0;
// }
try {
prepareExecution();
// prepareExecution();
QueryParameters queryParameters = new QueryParameters();
queryParameters.queryZoomLevel = mMapFileHeader
queryParameters.queryZoomLevel = sMapFileHeader
.getQueryZoomLevel(tile.zoomLevel);
// get and check the sub-file for the query zoom level
SubFileParameter subFileParameter = mMapFileHeader
SubFileParameter subFileParameter = sMapFileHeader
.getSubFileParameter(queryParameters.queryZoomLevel);
if (subFileParameter == null) {
LOG.warning("no sub-file for zoom level: "
@ -279,10 +240,15 @@ public class MapDatabase implements IMapDatabase {
*/
@Override
public MapFileInfo getMapFileInfo() {
if (mMapFileHeader == null) {
if (sMapFileHeader == null) {
throw new IllegalStateException("no map file is currently opened");
}
return mMapFileHeader.getMapFileInfo();
return sMapFileHeader.getMapFileInfo();
}
@Override
public String getMapProjection() {
return getMapFileInfo().projectionName;
}
/*
@ -300,6 +266,7 @@ public class MapDatabase implements IMapDatabase {
*/
@Override
public FileOpenResult openFile(File mapFile) {
try {
if (mapFile == null) {
// throw new IllegalArgumentException("mapFile must not be null");
@ -323,14 +290,23 @@ public class MapDatabase implements IMapDatabase {
mFileSize = mInputFile.length();
mReadBuffer = new ReadBuffer(mInputFile);
mMapFileHeader = new MapFileHeader();
FileOpenResult fileOpenResult = mMapFileHeader.readHeader(mReadBuffer,
if (instances > 0) {
instances++;
return FileOpenResult.SUCCESS;
}
sMapFileHeader = new MapFileHeader();
FileOpenResult fileOpenResult = sMapFileHeader.readHeader(mReadBuffer,
mFileSize);
if (!fileOpenResult.isSuccess()) {
closeFile();
return fileOpenResult;
}
prepareExecution();
instances++;
return FileOpenResult.SUCCESS;
} catch (IOException e) {
LOG.log(Level.SEVERE, null, e);
@ -340,6 +316,37 @@ public class MapDatabase implements IMapDatabase {
}
}
/*
* (non-Javadoc)
* @see org.mapsforge.map.reader.IMapDatabase#closeFile()
*/
@Override
public void closeFile() {
instances--;
if (instances > 0) {
mReadBuffer = null;
return;
}
try {
sMapFileHeader = null;
if (sDatabaseIndexCache != null) {
sDatabaseIndexCache.destroy();
sDatabaseIndexCache = null;
}
if (mInputFile != null) {
mInputFile.close();
mInputFile = null;
}
mReadBuffer = null;
} catch (IOException e) {
LOG.log(Level.SEVERE, null, e);
}
}
/**
* Logs the debug signatures of the current way and block.
*/
@ -351,8 +358,8 @@ public class MapDatabase implements IMapDatabase {
}
private void prepareExecution() {
if (mDatabaseIndexCache == null) {
mDatabaseIndexCache = new IndexCache(mInputFile, INDEX_CACHE_SIZE);
if (sDatabaseIndexCache == null) {
sDatabaseIndexCache = new IndexCache(mInputFile, INDEX_CACHE_SIZE);
}
}
@ -436,7 +443,7 @@ public class MapDatabase implements IMapDatabase {
long blockNumber = row * subFileParameter.blocksWidth + column;
// get the current index entry
long currentBlockIndexEntry = mDatabaseIndexCache.getIndexEntry(
long currentBlockIndexEntry = sDatabaseIndexCache.getIndexEntry(
subFileParameter, blockNumber);
// check if the current query would still return a water tile
@ -462,7 +469,7 @@ public class MapDatabase implements IMapDatabase {
nextBlockPointer = subFileParameter.subFileSize;
} else {
// get and check the next block pointer
nextBlockPointer = mDatabaseIndexCache.getIndexEntry(
nextBlockPointer = sDatabaseIndexCache.getIndexEntry(
subFileParameter, blockNumber + 1)
& BITMASK_INDEX_OFFSET;
if (nextBlockPointer < 1
@ -559,7 +566,7 @@ public class MapDatabase implements IMapDatabase {
* @return true if the POIs could be processed successfully, false otherwise.
*/
private boolean processPOIs(IMapDatabaseCallback mapDatabaseCallback, int numberOfPois) {
Tag[] poiTags = mMapFileHeader.getMapFileInfo().poiTags;
Tag[] poiTags = sMapFileHeader.getMapFileInfo().poiTags;
Tag[] tags = null;
for (int elementCounter = numberOfPois; elementCounter != 0; --elementCounter) {
@ -778,7 +785,7 @@ public class MapDatabase implements IMapDatabase {
int numberOfWays) {
Tag[] tags = null;
Tag[] wayTags = mMapFileHeader.getMapFileInfo().wayTags;
Tag[] wayTags = sMapFileHeader.getMapFileInfo().wayTags;
int[] textPos = new int[3];
// float[] labelPosition;
boolean skippedWays = false;
@ -957,7 +964,7 @@ public class MapDatabase implements IMapDatabase {
|| cumulatedNumberOfWays > MAXIMUM_ZOOM_TABLE_OBJECTS) {
LOG.warning("invalid cumulated number of ways in row " + row + ' '
+ cumulatedNumberOfWays);
if (mMapFileHeader.getMapFileInfo().debugFile) {
if (sMapFileHeader.getMapFileInfo().debugFile) {
LOG.warning(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
}
return null;

View File

@ -0,0 +1,513 @@
/*
* 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 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.mapsforge.database.pbmap;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.zip.GZIPInputStream;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.message.BasicHeader;
import org.mapsforge.core.BoundingBox;
import org.mapsforge.core.GeoPoint;
import org.mapsforge.core.Tag;
import org.mapsforge.core.Tile;
import org.mapsforge.core.WebMercator;
import org.mapsforge.database.FileOpenResult;
import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.IMapDatabaseCallback;
import org.mapsforge.database.MapFileInfo;
import android.net.http.AndroidHttpClient;
import android.util.Log;
/**
*
*
*/
public class MapDatabase implements IMapDatabase {
private static final String TAG = "MapDatabase";
private static final MapFileInfo mMapInfo =
new MapFileInfo(new BoundingBox(-180, -90, 180, 90),
new Byte((byte) 14), new GeoPoint(53.11, 8.85),
WebMercator.NAME, 0, 0, 0, "de", "comment", "author");
private boolean mOpenFile = false;
// private static final String URL = "http://city.informatik.uni-bremen.de:8020/test/%d/%d/%d.osmtile";
private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/test/%d/%d/%d.osmtile";
private static final Header encodingHeader =
new BasicHeader("Accept-Encoding", "gzip");
private static volatile HashMap<String, Tag> tagHash = new HashMap<String, Tag>(100);
private Tag[] curTags = new Tag[1000];
private int mCurTagCnt;
private AndroidHttpClient mClient;
private IMapDatabaseCallback mMapGenerator;
private float mScaleFactor;
@Override
public void executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) {
String url = String.format(URL, Integer.valueOf(tile.zoomLevel),
Long.valueOf(tile.tileX), Long.valueOf(tile.tileY));
HttpGet getRequest = new HttpGet(url);
getRequest.addHeader(encodingHeader);
mMapGenerator = mapDatabaseCallback;
mCurTagCnt = 0;
// using variable coordinate scalefactor to take advantage of
// variable byte encoded integers
mScaleFactor = 1 / 100f;
if (tile.zoomLevel < 12)
mScaleFactor = (float) Math.pow(2, (12 - tile.zoomLevel)) / 100f;
try {
HttpResponse response = mClient.execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.d(TAG, "Http response " + statusCode);
return;
}
final HttpEntity entity = response.getEntity();
if (entity == null) {
Log.d(TAG, "Somethings wrong? - no entity " + statusCode);
return;
}
InputStream is = null;
GZIPInputStream zis = null;
try {
is = entity.getContent();
zis = new GZIPInputStream(is);
decode(zis);
} finally {
if (zis != null)
zis.close();
if (is != null)
is.close();
entity.consumeContent();
}
} catch (Exception ex) {
getRequest.abort();
ex.printStackTrace();
}
}
@Override
public String getMapProjection() {
return WebMercator.NAME;
}
@Override
public MapFileInfo getMapFileInfo() {
return mMapInfo;
}
@Override
public boolean hasOpenFile() {
return mOpenFile;
}
@Override
public FileOpenResult openFile(File mapFile) {
mOpenFile = true;
mClient = AndroidHttpClient.newInstance("Android");
return new FileOpenResult();
}
@Override
public void closeFile() {
mOpenFile = false;
if (mClient != null)
mClient.close();
}
@Override
public String readString(int position) {
return null;
}
private static final int BUFFER_SIZE = 32768;
private final byte[] buffer = new byte[BUFFER_SIZE];
private int bufferPos;
private int bufferSize;
private InputStream inputStream;
private static final int TAG_TILE_TAGS = 1;
private static final int TAG_TILE_WAYS = 2;
private static final int TAG_TILE_NODES = 3;
private static final int TAG_WAY_TAGS = 1;
private static final int TAG_WAY_INDEX = 2;
private static final int TAG_WAY_COORDS = 3;
// private static final int TAG_NODE_TAGS = 1;
// private static final int TAG_NODE_COORDS = 2;
private int bytesRead;
private boolean decode(InputStream is) throws IOException {
inputStream = is;
bytesRead = 0;
bufferSize = 0;
bufferPos = 0;
while (true) {
// read tag and wire type
int val = decodeVarint32();
if (val == 0) {
// Log.d(TAG, "EOF, all good");
return true;
}
int tag = (val >> 3);
// int wireType = (val & 7);
// Log.d(TAG, "tile " + tag + " " + wireType);
switch (tag) {
case TAG_TILE_TAGS:
decodeTileTags();
break;
case TAG_TILE_WAYS:
decodeTileWays();
break;
case TAG_TILE_NODES:
decodeTileNodes();
break;
default:
Log.d(TAG, "invalid type for tile: " + tag);
return false;
}
}
}
private boolean decodeTileTags() throws IOException {
String tagString = decodeString();
Tag tag = tagHash.get(tagString);
if (tag == null) {
tag = new Tag(tagString);
tagHash.put(tagString, tag);
}
curTags[mCurTagCnt++] = tag;
// Log.d(TAG, "tag:" + tag);
return true;
}
private boolean decodeTileWays() throws IOException {
int bytes = decodeVarint32();
int end = bytesRead + bytes;
int indexCnt = 0;
int tagCnt = 0;
int coordCnt = 0;
while (bytesRead < end) {
// read tag and wire type
int val = decodeVarint32();
if (val == 0)
break;
int tag = (val >> 3);
// int wireType = val & 7;
// Log.d(TAG, "way " + tag + " " + wireType + " bytes:" + bytes);
switch (tag) {
case TAG_WAY_TAGS:
tagCnt = decodeWayTags();
break;
case TAG_WAY_INDEX:
indexCnt = decodeWayIndices();
break;
case TAG_WAY_COORDS:
coordCnt = decodeWayCoordinates();
break;
default:
Log.d(TAG, "invalid type for way: " + tag);
}
}
if (indexCnt == 0 || tagCnt == 0)
return false;
int[] index = new int[indexCnt];
int sum = 0;
for (int i = 0; i < indexCnt; i++) {
index[i] = tmpIndices[i] * 2;
sum += index[i];
}
Tag[] tags = new Tag[tagCnt];
for (int i = 0; i < tagCnt; i++)
tags[i] = curTags[tmpTags[i]];
float[] coords = tmpCoords;
int pos = 0;
if (coordCnt != sum) {
Log.d(TAG, "way length is wrong " + coordCnt + " " + sum);
return false;
}
float z = mScaleFactor;
for (int j = 0, m = indexCnt; j < m; j++) {
float lastX = 0;
float lastY = 0;
for (int n = index[j] + pos; pos < n; pos += 2) {
lastX = coords[pos] = (coords[pos] * z) + lastX;
lastY = coords[pos + 1] = (coords[pos + 1] * z) + lastY;
}
}
mMapGenerator.renderWay((byte) 0, tags, coords, index, true);
return true;
}
private boolean decodeTileNodes() throws IOException {
int bytes = decodeVarint32();
Log.d(TAG, "way nodes " + bytes);
return true;
}
private int MAX_WAY_COORDS = 32768;
private int MAX_WAY_INDICES = 1000;
private int[] tmpTags = new int[32];
private int[] tmpIndices = new int[MAX_WAY_INDICES];
private float[] tmpCoords = new float[MAX_WAY_COORDS];
// private boolean ensureBufferSize(int size) throws IOException {
// if (size > (bufferSize - bufferPos))
// readBuffer(size - (bufferSize - bufferPos));
//
// return true;
// }
private int decodeWayTags() throws IOException {
int bytes = decodeVarint32();
// Log.d(TAG, "way tags: " + bytes);
int cnt = 0;
int end = bytesRead + bytes;
while (bytesRead < end)
tmpTags[cnt++] = decodeVarint32();
return cnt;
}
private int decodeWayIndices() throws IOException {
int bytes = decodeVarint32();
// Log.d(TAG, "way indices: " + bytes);
int cnt = 0;
int end = bytesRead + bytes;
while (bytesRead < end) {
int val = decodeVarint32();
if (cnt >= MAX_WAY_INDICES) {
MAX_WAY_INDICES += 128;
Log.d(TAG, "increase indices array " + MAX_WAY_INDICES);
int[] tmp = new int[MAX_WAY_INDICES];
System.arraycopy(tmpIndices, 0, tmp, 0, cnt);
tmpIndices = tmp;
}
tmpIndices[cnt++] = val;
}
return cnt;
}
private int decodeWayCoordinates() throws IOException {
int bytes = decodeVarint32();
int cnt = 0;
int end = bytesRead + bytes;
while (bytesRead < end) {
int val = decodeZigZag32(decodeVarint32());
if (cnt >= MAX_WAY_COORDS) {
MAX_WAY_COORDS += 128;
Log.d(TAG, "increase coords array " + MAX_WAY_COORDS);
float[] tmp = new float[MAX_WAY_COORDS];
System.arraycopy(tmpCoords, 0, tmp, 0, cnt);
tmpCoords = tmp;
}
tmpCoords[cnt++] = val;
}
return cnt;
}
private void readBuffer() throws IOException {
int len = inputStream.read(buffer, 0, BUFFER_SIZE);
if (len < 0) {
buffer[bufferPos] = 0;
// Log.d(TAG, " nothing to read... pos " + bufferPos + ", size "
// + bufferSize + ", read " + bytesRead);
return;
}
bufferSize = len;
bufferPos = 0;
// Log.d(TAG, "pos " + bufferPos + ", size " + bufferSize + ", read "
// + bytesRead);
}
private void readBuffer(int size) throws IOException {
if (size < (bufferSize - bufferPos))
return;
if (size > BUFFER_SIZE) {
Log.d(TAG, "EEEK too large");
// FIXME throw exception, but frankly better sanitize tile data on compilation
// this only happen with Strings larger than 32kb
return;
}
if ((size - bufferSize) + bufferPos > BUFFER_SIZE) {
// copy bytes left to read from buffer to the beginning of buffer
System.arraycopy(buffer, bufferPos, buffer, 0, bufferSize - bufferPos);
bufferPos = 0;
}
while ((bufferSize - bufferPos) < size) {
// read until requested size is available in buffer
int len = inputStream.read(buffer, bufferSize, BUFFER_SIZE - bufferSize);
if (len < 0) {
buffer[bufferSize - 1] = 0; // FIXME is this needed?
break;
}
bufferSize += len;
}
// Log.d(TAG, "needed " + size + " pos " + bufferPos + ", size "
// + bufferSize
// + ", read " + bytesRead);
}
/* All code below is taken from or based on Google's Protocol Buffers implementation: */
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
private byte readRawByte() throws IOException {
if (bufferPos == bufferSize) {
readBuffer();
}
bytesRead++;
return buffer[bufferPos++];
}
private int decodeVarint32() throws IOException {
byte tmp = readRawByte();
if (tmp >= 0) {
return tmp;
}
int result = tmp & 0x7f;
if ((tmp = readRawByte()) >= 0) {
return result | tmp << 7;
}
result |= (tmp & 0x7f) << 7;
if ((tmp = readRawByte()) >= 0) {
return result | tmp << 14;
}
result |= (tmp & 0x7f) << 14;
if ((tmp = readRawByte()) >= 0) {
return result | tmp << 21;
}
result |= (tmp & 0x7f) << 21;
result |= (tmp = readRawByte()) << 28;
if (tmp < 0) {
// Discard upper 32 bits.
for (int i = 0; i < 5; i++) {
if (readRawByte() >= 0) {
return result;
}
}
Log.d(TAG, "EEK malformedVarint");
// FIXME throw some poo
}
return result;
}
private String decodeString() throws IOException {
final int size = decodeVarint32();
readBuffer(size);
final String result = new String(buffer, bufferPos, size, "UTF-8");
bufferPos += size;
bytesRead += size;
return result;
}
public static int decodeZigZag32(final int n) {
return (n >>> 1) ^ -(n & 1);
}
}

View File

@ -26,9 +26,9 @@ import java.util.Properties;
import org.mapsforge.core.BoundingBox;
import org.mapsforge.core.GeoPoint;
import org.mapsforge.core.WebMercator;
import org.mapsforge.core.Tag;
import org.mapsforge.core.Tile;
import org.mapsforge.core.WebMercator;
import org.mapsforge.database.FileOpenResult;
import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.IMapDatabaseCallback;
@ -40,7 +40,7 @@ import org.postgresql.PGConnection;
*
*/
public class MapDatabase implements IMapDatabase {
private static final String QUERY = "SELECT * FROM __get_tile(?,?,?)";
private static final String QUERY = "SELECT tags, geom FROM __get_tile(?,?,?)";
private final float mScale = 1; // 1000000.0f;
@ -55,16 +55,13 @@ public class MapDatabase implements IMapDatabase {
new MapFileInfo(new BoundingBox(-180, -85, 180, 85),
new Byte((byte) 14), new GeoPoint(53.11, 8.85),
WebMercator.NAME,
0, 0, 0, "de", "yo!", "hannes");
// new MapFileInfo(new BoundingBox(-180, -90, 180, 90),
// new Byte((byte) 0), null, "Mercator",
// 0, 0, 0, "de", "yo!", "by me");
0, 0, 0, "de", "comment", "author");
private boolean mOpenFile = false;
private Connection connection = null;
private static HashMap<Entry<String, String>, Tag> tagHash = new HashMap<Entry<String, String>, Tag>(
100);
private static volatile HashMap<Entry<String, String>, Tag> tagHash =
new HashMap<Entry<String, String>, Tag>(100);
private PreparedStatement prepQuery = null;
private boolean connect() {
@ -123,7 +120,6 @@ public class MapDatabase implements IMapDatabase {
byte[] b = null;
PGHStore h = null;
// long id;
try {
while (r != null && r.next()) {
@ -131,9 +127,7 @@ public class MapDatabase implements IMapDatabase {
mCoordPos = 0;
try {
// id = r.getLong(1);
Object obj = r.getObject(2);
Object obj = r.getObject(1);
h = null;
if (obj instanceof PGHStore)
@ -141,7 +135,7 @@ public class MapDatabase implements IMapDatabase {
else
continue;
b = r.getBytes(3);
b = r.getBytes(2);
} catch (SQLException e) {
e.printStackTrace();
@ -184,6 +178,11 @@ public class MapDatabase implements IMapDatabase {
}
}
@Override
public String getMapProjection() {
return WebMercator.NAME;
}
@Override
public MapFileInfo getMapFileInfo() {
return mMapInfo;