- 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 <uses-sdk
android:minSdkVersion="10" android:minSdkVersion="10"
android:targetSdkVersion="15" /> android:targetSdkVersion="16" />
<application <application
android:icon="@drawable/globe2" android:icon="@drawable/globe2"
android:label="@string/application_name" android:label="@string/application_name"
android:theme="@style/Theme.TileMap" > android:theme="@style/Theme.TileMap" >
<activity
<activity android:name="org.mapsforge.app.TileMap" > android:name="org.mapsforge.app.TileMap"
android:configChanges="orientation|screenSize" >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@ -28,6 +29,6 @@
</activity> </activity>
<activity android:name=".preferences.EditPreferences" /> <activity android:name=".preferences.EditPreferences" />
<activity android:name=".filepicker.FilePicker" /> <activity android:name=".filepicker.FilePicker" />
</application>
</application>
</manifest> </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"> <string-array name="preferences_map_generator_values">
<item>Mapfile</item> <item>Mapfile</item>
<item>PostGIS</item> <item>PostGIS</item>
<item>OpenScienceMap</item>
</string-array> </string-array>
<string-array name="preferences_scale_bar_unit_values"> <string-array name="preferences_scale_bar_unit_values">

View File

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

View File

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

View File

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

View File

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

View File

@ -14,6 +14,7 @@
*/ */
package org.mapsforge.android; package org.mapsforge.android;
import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.MapGeneratorJob; import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import android.opengl.GLSurfaceView; 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 * @param mapGeneratorJob
@ -31,9 +32,8 @@ public interface MapRenderer extends GLSurfaceView.Renderer {
public boolean passTile(MapGeneratorJob mapGeneratorJob); public boolean passTile(MapGeneratorJob mapGeneratorJob);
/** /**
* @return true when tile passed to renderer is processed false otherwise. * @return true when tile passed to renderer is processed false otherwise. used to lock overwriting resources passed
* used to lock overwriting resources passed with the tile * with the tile (e.g. lock until bitmap is loaded to texture)
* (e.g. lock until bitmap is loaded to texture)
*/ */
public boolean processedTile(); public boolean processedTile();
@ -44,4 +44,6 @@ public interface MapRenderer extends GLSurfaceView.Renderer {
* ... * ...
*/ */
public void redrawTiles(boolean clear); 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.File;
import java.io.FileNotFoundException; 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.input.TouchHandler;
import org.mapsforge.android.mapgenerator.IMapGenerator; import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.JobParameters; import org.mapsforge.android.mapgenerator.JobParameters;
import org.mapsforge.android.mapgenerator.JobQueue; import org.mapsforge.android.mapgenerator.JobQueue;
import org.mapsforge.android.mapgenerator.JobTheme;
import org.mapsforge.android.mapgenerator.MapDatabaseFactory; import org.mapsforge.android.mapgenerator.MapDatabaseFactory;
import org.mapsforge.android.mapgenerator.MapDatabaseInternal; import org.mapsforge.android.mapgenerator.MapDatabases;
import org.mapsforge.android.mapgenerator.MapGeneratorFactory; import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.mapgenerator.MapGeneratorInternal; import org.mapsforge.android.mapgenerator.MapRendererFactory;
import org.mapsforge.android.mapgenerator.MapRenderers;
import org.mapsforge.android.mapgenerator.MapWorker; import org.mapsforge.android.mapgenerator.MapWorker;
import org.mapsforge.android.mapgenerator.Theme;
import org.mapsforge.android.rendertheme.ExternalRenderTheme; import org.mapsforge.android.rendertheme.ExternalRenderTheme;
import org.mapsforge.android.rendertheme.InternalRenderTheme; 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.android.utils.GlConfigChooser;
import org.mapsforge.core.GeoPoint; import org.mapsforge.core.GeoPoint;
import org.mapsforge.core.MapPosition; import org.mapsforge.core.MapPosition;
import org.mapsforge.database.FileOpenResult; import org.mapsforge.database.FileOpenResult;
import org.mapsforge.database.IMapDatabase; import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.MapFileInfo;
import org.mapsforge.database.mapfile.MapDatabase; import org.mapsforge.database.mapfile.MapDatabase;
import org.xml.sax.SAXException;
import android.content.Context; import android.content.Context;
import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView;
@ -49,8 +59,7 @@ import android.view.MotionEvent;
* <p> * <p>
* This implementation supports offline map rendering as well as downloading map images (tiles) over an Internet * 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 * 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 * {@link #setMapDatabase(MapDatabases)} method. Some MapView parameters depend on the selected operation mode.
* mode.
* <p> * <p>
* In offline rendering mode a special database file is required which contains the map data. Map files can be stored in * 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 * 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; public static final InternalRenderTheme DEFAULT_RENDER_THEME = InternalRenderTheme.OSMARENDER;
private static final float DEFAULT_TEXT_SCALE = 1; 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 MapController mMapController;
// private final MapMover mMapMover; // private final MapMover mMapMover;
// private final ZoomAnimator mZoomAnimator; // private final ZoomAnimator mZoomAnimator;
// private final MapScaleBar mMapScaleBar;
private final MapScaleBar mMapScaleBar;
private final MapViewPosition mMapViewPosition; private final MapViewPosition mMapViewPosition;
private final MapZoomControls mMapZoomControls; private final MapZoomControls mMapZoomControls;
@ -80,10 +89,11 @@ public class MapView extends GLSurfaceView {
private final TouchHandler mTouchEventHandler; private final TouchHandler mTouchEventHandler;
private IMapDatabase mMapDatabase; private IMapDatabase mMapDatabase;
private IMapGenerator mMapGenerator; private MapDatabases mMapDatabaseType;
private MapRenderer mMapRenderer; private IMapRenderer mMapRenderer;
private JobQueue mJobQueue; private JobQueue mJobQueue;
private MapWorker mMapWorker; private MapWorker mMapWorkers[];
private int mNumMapWorkers = 6;
private JobParameters mJobParameters; private JobParameters mJobParameters;
private DebugSettings mDebugSettings; private DebugSettings mDebugSettings;
private String mMapFile; private String mMapFile;
@ -95,9 +105,7 @@ public class MapView extends GLSurfaceView {
* if the context object is not an instance of {@link MapActivity} . * if the context object is not an instance of {@link MapActivity} .
*/ */
public MapView(Context context) { public MapView(Context context) {
this(context, null, this(context, null, MapRenderers.GL_RENDERER, MapDatabases.MAP_READER);
MapGeneratorFactory.createMapGenerator(MapGeneratorInternal.GL_RENDERER),
MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.MAP_READER));
} }
/** /**
@ -110,25 +118,12 @@ public class MapView extends GLSurfaceView {
*/ */
public MapView(Context context, AttributeSet attributeSet) { public MapView(Context context, AttributeSet attributeSet) {
this(context, attributeSet, this(context, attributeSet,
MapGeneratorFactory.createMapGenerator(attributeSet), MapRendererFactory.getMapGenerator(attributeSet),
MapDatabaseFactory.createMapDatabase(attributeSet)); MapDatabaseFactory.getMapDatabase(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));
} }
private MapView(Context context, AttributeSet attributeSet, private MapView(Context context, AttributeSet attributeSet,
IMapGenerator mapGenerator, IMapDatabase mapDatabase) { MapRenderers mapGeneratorType, MapDatabases mapDatabaseType) {
super(context, attributeSet); super(context, attributeSet);
@ -147,46 +142,63 @@ public class MapView extends GLSurfaceView {
mJobParameters = new JobParameters(DEFAULT_RENDER_THEME, DEFAULT_TEXT_SCALE); mJobParameters = new JobParameters(DEFAULT_RENDER_THEME, DEFAULT_TEXT_SCALE);
mMapController = new MapController(this); mMapController = new MapController(this);
// mMapDatabase = MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.POSTGIS_READER); mMapDatabaseType = mapDatabaseType;
// mMapDatabase = MapDatabaseFactory.createMapDatabase(MapDatabaseInternal.JSON_READER);
mMapDatabase = mapDatabase;
mMapViewPosition = new MapViewPosition(this); mMapViewPosition = new MapViewPosition(this);
mMapScaleBar = new MapScaleBar(this); // mMapScaleBar = new MapScaleBar(this);
mMapZoomControls = new MapZoomControls(mapActivity, this); mMapZoomControls = new MapZoomControls(mapActivity, this);
mProjection = new MapViewProjection(this); mProjection = new MapViewProjection(this);
mTouchEventHandler = new TouchHandler(mapActivity, this); mTouchEventHandler = new TouchHandler(mapActivity, this);
mJobQueue = new JobQueue(this); mJobQueue = new JobQueue(this);
mMapWorker = new MapWorker(this);
mMapWorker.start();
// mMapMover = new MapMover(this); // mMapMover = new MapMover(this);
// mMapMover.start(); // mMapMover.start();
// mZoomAnimator = new ZoomAnimator(this); // mZoomAnimator = new ZoomAnimator(this);
// mZoomAnimator.start(); // mZoomAnimator.start();
setMapGeneratorInternal(mapGenerator); mMapRenderer = MapRendererFactory.createMapRenderer(this, mapGeneratorType);
mMapWorkers = new MapWorker[mNumMapWorkers];
GeoPoint startPoint = mMapGenerator.getStartPoint(); for (int i = 0; i < mNumMapWorkers; i++) {
if (startPoint != null) { IMapDatabase mapDatabase = MapDatabaseFactory
mMapViewPosition.setMapCenter(startPoint); .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(); setRenderTheme(InternalRenderTheme.OSMARENDER);
if (startZoomLevel != null) {
mMapViewPosition.setZoomLevel(startZoomLevel.byteValue());
}
mapActivity.registerMapView(this); mapActivity.registerMapView(this);
setEGLConfigChooser(new GlConfigChooser()); setEGLConfigChooser(new GlConfigChooser());
setEGLContextClientVersion(2); setEGLContextClientVersion(2);
mMapRenderer = mMapGenerator.getMapRenderer(this);
setRenderer(mMapRenderer); setRenderer(mMapRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 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 mMapFile;
} }
/**
* @return the currently used MapGenerator (may be null).
*/
public IMapGenerator getMapGenerator() {
return mMapGenerator;
}
// /** // /**
// * @return the MapMover which is used by this MapView. // * @return the MapMover which is used by this MapView.
// */ // */
@ -245,19 +250,19 @@ public class MapView extends GLSurfaceView {
return mMapViewPosition; return mMapViewPosition;
} }
/** // /**
* @return the scale bar which is used in this MapView. // * @return the scale bar which is used in this MapView.
*/ // */
public MapScaleBar getMapScaleBar() { // public MapScaleBar getMapScaleBar() {
return mMapScaleBar; // return mMapScaleBar;
} // }
/** // /**
* @return the zoom controls instance which is used in this MapView. // * @return the zoom controls instance which is used in this MapView.
*/ // */
public MapZoomControls getMapZoomControls() { // public MapZoomControls getMapZoomControls() {
return mMapZoomControls; // return mMapZoomControls;
} // }
/** /**
* @return the currently used projection of the map. Do not keep this object for a longer time. * @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(); // mZoomAnimator.pause();
// mMapMover.pause(); // mMapMover.pause();
mMapWorker.pause();
// mZoomAnimator.awaitPausing(); // mZoomAnimator.awaitPausing();
// mMapMover.awaitPausing(); // mMapMover.awaitPausing();
mMapWorker.awaitPausing();
// mZoomAnimator.proceed(); // mZoomAnimator.proceed();
// mMapMover.stopMove(); // mMapMover.stopMove();
// mMapMover.proceed(); // mMapMover.proceed();
mMapWorker.proceed();
mMapDatabase.closeFile(); boolean initialized = false;
if (mapFile != null) mJobQueue.clear();
fileOpenResult = mMapDatabase.openFile(new File(mapFile));
else
fileOpenResult = mMapDatabase.openFile(null);
if (fileOpenResult != null && fileOpenResult.isSuccess()) { mapWorkersPause();
mMapFile = mapFile;
GeoPoint startPoint = mMapGenerator.getStartPoint(); for (MapWorker mapWorker : mMapWorkers) {
if (startPoint != null) {
Log.d(TAG, "mapfile got startpoint"); IMapGenerator mapGenerator = mapWorker.getMapGenerator();
mMapViewPosition.setMapCenter(startPoint); 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(); mapWorkersProceed();
if (startZoomLevel != null) {
Log.d(TAG, "mapfile got start zoomlevel");
mMapViewPosition.setZoomLevel(startZoomLevel.byteValue());
}
if (initialized) {
clearAndRedrawMapView(); clearAndRedrawMapView();
Log.d(TAG, "mapfile set"); Log.d(TAG, "mapfile set");
return true; return true;
@ -404,76 +413,61 @@ public class MapView extends GLSurfaceView {
return false; return false;
} }
/** private GeoPoint getStartPoint() {
* Sets the MapGenerator for this MapView. if (mMapDatabase != null && mMapDatabase.hasOpenFile()) {
* MapFileInfo mapFileInfo = mMapDatabase.getMapFileInfo();
* @param mapGenerator if (mapFileInfo.startPosition != null) {
* the new MapGenerator. return mapFileInfo.startPosition;
*/ } else if (mapFileInfo.mapCenter != null) {
public void setMapGenerator(IMapGenerator mapGenerator) { return mapFileInfo.mapCenter;
}
if (mMapGenerator != mapGenerator) {
setMapGeneratorInternal(mapGenerator);
clearAndRedrawMapView();
} }
return null;
} }
private void setMapGeneratorInternal(IMapGenerator mapGenerator) { private Byte getStartZoomLevel() {
if (mapGenerator == null) { if (mMapDatabase != null && mMapDatabase.hasOpenFile()) {
throw new IllegalArgumentException("mapGenerator must not be null"); MapFileInfo mapFileInfo = mMapDatabase.getMapFileInfo();
if (mapFileInfo.startZoomLevel != null) {
return mapFileInfo.startZoomLevel;
}
} }
mapGenerator.setMapDatabase(mMapDatabase); return DEFAULT_START_ZOOM_LEVEL;
mMapGenerator = mapGenerator;
mMapWorker.setMapGenerator(mMapGenerator);
} }
/** /**
* Sets the MapDatabase for this MapView. * Sets the MapDatabase for this MapView.
* *
* @param mapDatabase * @param mapDatabaseType
* the new MapDatabase. * the new MapDatabase.
*/ */
public void setMapDatabase(IMapDatabase mapDatabase) {
Log.d(TAG, "setMapDatabase " + mapDatabase.getClass());
if (mMapDatabase != mapDatabase) {
if (mMapDatabase != null) public void setMapDatabase(MapDatabases mapDatabaseType) {
mMapDatabase.closeFile(); IMapGenerator mapGenerator;
setMapDatabaseInternal(mapDatabase); Log.d(TAG, "setMapDatabase " + mapDatabaseType.name());
// clearAndRedrawMapView(); if (mMapDatabaseType == mapDatabaseType)
} return;
}
private void setMapDatabaseInternal(IMapDatabase mapDatabase) { mapWorkersPause();
if (mapDatabase == null) {
throw new IllegalArgumentException("MapDatabase must not be null");
}
if (!mMapWorker.isPausing()) { for (MapWorker mapWorker : mMapWorkers) {
mMapWorker.pause(); mapGenerator = mapWorker.getMapGenerator();
mMapWorker.awaitPausing();
mapGenerator.setMapDatabase(MapDatabaseFactory
.createMapDatabase(mapDatabaseType));
} }
mJobQueue.clear(); mJobQueue.clear();
mMapDatabase = mapDatabase;
mMapGenerator.setMapDatabase(mMapDatabase);
Log.d(TAG, "setMapDatabaseInternal " + mapDatabase.getClass());
String mapFile = mMapFile; String mapFile = mMapFile;
mMapFile = null; mMapFile = null;
setMapFile(mapFile); setMapFile(mapFile);
mMapWorker.proceed(); mapWorkersProceed();
// mMapWorker.setMapDatabase(mMapDatabase);
} }
/** /**
@ -489,8 +483,7 @@ public class MapView extends GLSurfaceView {
throw new IllegalArgumentException("render theme must not be null"); throw new IllegalArgumentException("render theme must not be null");
} }
Log.d(TAG, "set rendertheme " + internalRenderTheme); setRenderTheme((Theme) internalRenderTheme);
mJobParameters = new JobParameters(internalRenderTheme, mJobParameters.textScale);
clearAndRedrawMapView(); clearAndRedrawMapView();
} }
@ -510,12 +503,40 @@ public class MapView extends GLSurfaceView {
throw new IllegalArgumentException("render theme path must not be null"); throw new IllegalArgumentException("render theme path must not be null");
} }
JobTheme jobTheme = new ExternalRenderTheme(renderThemePath); setRenderTheme(new ExternalRenderTheme(renderThemePath));
mJobParameters = new JobParameters(jobTheme, mJobParameters.textScale);
clearAndRedrawMapView(); 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. * 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. * the new text scale for the map rendering.
*/ */
public void setTextScale(float textScale) { public void setTextScale(float textScale) {
mJobParameters = new JobParameters(mJobParameters.jobTheme, textScale); mJobParameters = new JobParameters(mJobParameters.theme, textScale);
clearAndRedrawMapView(); clearAndRedrawMapView();
} }
@ -583,28 +604,33 @@ public class MapView extends GLSurfaceView {
@Override @Override
protected synchronized void onSizeChanged(int width, int height, int oldWidth, protected synchronized void onSizeChanged(int width, int height, int oldWidth,
int oldHeight) { int oldHeight) {
mMapWorker.pause(); for (MapWorker mapWorker : mMapWorkers) {
mMapWorker.awaitPausing(); mapWorker.pause();
super.onSizeChanged(width, height, oldWidth, oldHeight); mapWorker.awaitPausing();
mMapWorker.proceed(); super.onSizeChanged(width, height, oldWidth, oldHeight);
mapWorker.proceed();
}
// redrawTiles(); // redrawTiles();
} }
void destroy() { void destroy() {
// mMapMover.interrupt(); // mMapMover.interrupt();
mMapWorker.interrupt();
// mZoomAnimator.interrupt(); // mZoomAnimator.interrupt();
try { for (MapWorker mapWorker : mMapWorkers) {
mMapWorker.join(); mapWorker.interrupt();
} catch (InterruptedException e) {
// restore the interrupted status try {
Thread.currentThread().interrupt(); mapWorker.join();
} catch (InterruptedException e) {
// restore the interrupted status
Thread.currentThread().interrupt();
}
IMapDatabase mapDatabase = mapWorker.getMapGenerator().getMapDatabase();
mapDatabase.closeFile();
} }
mMapScaleBar.destroy(); // mMapScaleBar.destroy();
mMapDatabase.closeFile();
} }
@ -612,8 +638,9 @@ public class MapView extends GLSurfaceView {
* @return the maximum possible zoom level. * @return the maximum possible zoom level.
*/ */
byte getMaximumPossibleZoomLevel() { byte getMaximumPossibleZoomLevel() {
return (byte) Math.min(mMapZoomControls.getZoomLevelMax(), return (byte) 20;
mMapGenerator.getZoomLevelMax()); // FIXME Math.min(mMapZoomControls.getZoomLevelMax(),
// mMapGenerator.getZoomLevelMax());
} }
/** /**
@ -639,7 +666,9 @@ public class MapView extends GLSurfaceView {
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
mMapWorker.pause(); for (MapWorker mapWorker : mMapWorkers)
mapWorker.pause();
// mMapMover.pause(); // mMapMover.pause();
// mZoomAnimator.pause(); // mZoomAnimator.pause();
} }
@ -647,7 +676,9 @@ public class MapView extends GLSurfaceView {
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
mMapWorker.proceed(); for (MapWorker mapWorker : mMapWorkers)
mapWorker.proceed();
// mMapMover.proceed(); // mMapMover.proceed();
// mZoomAnimator.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() { public void addJobs(ArrayList<MapGeneratorJob> jobs) {
return mMapWorker; 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 { public class MapViewPosition {
private static float MAX_SCALE = 2.0f; private static float MAX_SCALE = 2.0f;
private static float MIN_SCALE = 1.0f; private static float MIN_SCALE = 1.0f;
private static int MAX_ZOOMLEVEL = 16;
private double mLatitude; private double mLatitude;
private double mLongitude; private double mLongitude;
@ -162,12 +163,14 @@ public class MapViewPosition {
float s = mScale * scale; float s = mScale * scale;
if (s >= MAX_SCALE) { if (s >= MAX_SCALE) {
if (s > 8)
byte z = (byte) FloatMath.sqrt(s);
if (z != 0 && mZoomLevel == 20)
return; 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) { } else if (s < MIN_SCALE) {
byte z = (byte) FloatMath.sqrt(1 / s); byte z = (byte) FloatMath.sqrt(1 / s);
if (z != 0 && mZoomLevel == 1) if (z != 0 && mZoomLevel == 1)

View File

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

View File

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

View File

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

View File

@ -14,6 +14,57 @@
*/ */
package org.mapsforge.android.glrenderer; 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.FloatBuffer;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@ -25,10 +76,9 @@ import javax.microedition.khronos.opengles.GL10;
import org.mapsforge.android.DebugSettings; import org.mapsforge.android.DebugSettings;
import org.mapsforge.android.MapView; import org.mapsforge.android.MapView;
import org.mapsforge.android.mapgenerator.JobParameters;
import org.mapsforge.android.mapgenerator.IMapGenerator; import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.JobParameters;
import org.mapsforge.android.mapgenerator.MapGeneratorJob; import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.mapgenerator.MapWorker;
import org.mapsforge.android.mapgenerator.TileCacheKey; import org.mapsforge.android.mapgenerator.TileCacheKey;
import org.mapsforge.android.mapgenerator.TileDistanceSort; import org.mapsforge.android.mapgenerator.TileDistanceSort;
import org.mapsforge.android.utils.GlConfigChooser; 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 * 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 * 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 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_MAX = 400;
private static int CACHE_TILES = CACHE_TILES_MAX; 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 OES_HALF_FLOAT = 0x8D61;
private static final int FLOAT_BYTES = 4; 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 static int STENCIL_BITS = 8;
private final MapView mMapView; private final MapView mMapView;
private final MapWorker mMapWorker;
private final ArrayList<MapGeneratorJob> mJobList; private final ArrayList<MapGeneratorJob> mJobList;
private final ArrayList<VertexBufferObject> mVBOs; private final ArrayList<VertexBufferObject> mVBOs;
private final TileCacheKey mTileCacheKey; private final TileCacheKey mTileCacheKey;
@ -88,9 +139,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
// current center tile // current center tile
private long mTileX, mTileY; private long mTileX, mTileY;
private FloatBuffer floatBuffer = null; private FloatBuffer floatBuffer[];
// private ByteBuffer byteBuffer = null; private ShortBuffer shortBuffer[];
private ShortBuffer shortBuffer = null;
boolean useHalfFloat = false; boolean useHalfFloat = false;
@ -147,7 +197,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
public MapRenderer(MapView mapView) { public MapRenderer(MapView mapView) {
Log.d(TAG, "init MapRenderer"); Log.d(TAG, "init MapRenderer");
mMapView = mapView; mMapView = mapView;
mMapWorker = mapView.getMapWorker();
mDebugSettings = mapView.getDebugSettings(); mDebugSettings = mapView.getDebugSettings();
mVBOs = new ArrayList<VertexBufferObject>(); mVBOs = new ArrayList<VertexBufferObject>();
@ -316,7 +365,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
mJobList.clear(); mJobList.clear();
mJobParameter = mMapView.getJobParameters(); mJobParameter = mMapView.getJobParameters();
IMapGenerator mapGenerator = mMapView.getMapGenerator();
int tiles = 0; int tiles = 0;
if (newTiles == null) if (newTiles == null)
return false; return false;
@ -376,19 +424,19 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
newTiles.tiles[tiles++] = tile; newTiles.tiles[tiles++] = tile;
if (!tile.isDrawn && !tile.newData && !tile.isLoading) { if (!tile.isDrawn && !tile.newData && !tile.isLoading) {
MapGeneratorJob job = new MapGeneratorJob(tile, mapGenerator, MapGeneratorJob job = new MapGeneratorJob(tile, mJobParameter,
mJobParameter, mDebugSettings); mDebugSettings);
mJobList.add(job); mJobList.add(job);
} }
// prefetch parent // prefetch parent
if (tile.parent != null && !tile.parent.isDrawn && !tile.parent.newData // if (tile.parent != null && !tile.parent.isDrawn && !tile.parent.newData
&& !tile.parent.isLoading) { // && !tile.parent.isLoading) {
MapGeneratorJob job = new MapGeneratorJob(tile.parent, mapGenerator, // MapGeneratorJob job = new MapGeneratorJob(tile.parent, mJobParameter,
mJobParameter, mDebugSettings); // mDebugSettings);
if (!mJobList.contains(job)) // if (!mJobList.contains(job))
mJobList.add(job); // mJobList.add(job);
} // }
} }
} }
@ -419,12 +467,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
limitCache(removes); limitCache(removes);
if (mJobList.size() > 0) { if (mJobList.size() > 0)
mMapView.getJobQueue().setJobs(mJobList); mMapView.addJobs(mJobList);
synchronized (mMapWorker) {
mMapWorker.notify();
}
}
return true; return true;
} }
@ -513,7 +557,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
@Override @Override
public boolean passTile(MapGeneratorJob mapGeneratorJob) { public boolean passTile(MapGeneratorJob mapGeneratorJob) {
if (!timing) if (!timing && mapGeneratorJob.tile.isVisible)
mMapView.requestRender(); mMapView.requestRender();
return true; return true;
} }
@ -524,10 +568,10 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
boolean blend = false; boolean blend = false;
// draw to framebuffer // draw to framebuffer
GLES20.glColorMask(true, true, true, true); glColorMask(true, true, true, true);
// do not modify stencil buffer // do not modify stencil buffer
GLES20.glStencilMask(0); glStencilMask(0);
for (int c = 0; c < count; c++) { for (int c = 0; c < count; c++) {
PolygonLayer l = mFillPolys[c]; PolygonLayer l = mFillPolys[c];
@ -541,26 +585,26 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
alpha = 1.0f; alpha = 1.0f;
if (!blend) { if (!blend) {
GLES20.glEnable(GLES20.GL_BLEND); glEnable(GL_BLEND);
blend = true; blend = true;
} }
} else if (blend) { } else if (blend) {
GLES20.glDisable(GLES20.GL_BLEND); glDisable(GL_BLEND);
blend = false; blend = false;
} }
GLES20.glUniform4f(gPolygonColorHandle, glUniform4f(gPolygonColorHandle,
l.colors[0], l.colors[1], l.colors[2], alpha); l.colors[0], l.colors[1], l.colors[2], alpha);
// set stencil buffer mask used to draw this layer // 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 // draw tile fill coordinates
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
} }
if (blend) if (blend)
GLES20.glDisable(GLES20.GL_BLEND); glDisable(GL_BLEND);
} }
private boolean drawPolygons(GLMapTile tile, int diff) { 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) if (tile.polygonLayers == null || tile.polygonLayers.array == null)
return true; 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) { if (useHalfFloat) {
GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2, glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
OES_HALF_FLOAT, false, 0, OES_HALF_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET); POLYGON_VERTICES_DATA_POS_OFFSET);
} else { } else {
GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2, glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
GLES20.GL_FLOAT, false, 0, GL_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET); POLYGON_VERTICES_DATA_POS_OFFSET);
}
// glBindBuffer(GL_ARRAY_BUFFER, 0);
} }
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
setMatrix(tile, diff); setMatrix(tile, diff);
GLES20.glUniformMatrix4fv(gPolygonMatrixHandle, 1, false, mMVPMatrix, 0); glUniformMatrix4fv(gPolygonMatrixHandle, 1, false, mMVPMatrix, 0);
boolean firstPass = true; boolean firstPass = true;
for (int i = 0, n = tile.polygonLayers.array.length; i < n; i++) { for (int i = 0, n = tile.polygonLayers.array.length; i < n; i++) {
PolygonLayer l = tile.polygonLayers.array[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) // fade out polygon layers (set in RederTheme)
if (l.fadeLevel > 0 && l.fadeLevel > mDrawZ) if (l.fadeLevel > 0 && l.fadeLevel > mDrawZ)
continue; 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; mFillPolys[cnt] = l;
// set stencil mask to draw to // 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 // draw up to 8 layers into stencil buffer
if (cnt == STENCIL_BITS) { if (cnt == STENCIL_BITS) {
@ -634,47 +683,54 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
} }
if (cnt > 0) if (cnt > 0) {
fillPolygons(cnt); fillPolygons(cnt);
// eeek, nexus! - cant do old-school polygons
// glFinish();
}
return true; return true;
} }
private int mLastBoundVBO;
private boolean drawTriangles(GLMapTile tile, int diff) { private boolean drawTriangles(GLMapTile tile, int diff) {
if (tile.meshLayers == null || tile.meshLayers.array == null) if (tile.meshLayers == null || tile.meshLayers.array == null)
return true; 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) { if (useHalfFloat) {
GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2, glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
OES_HALF_FLOAT, false, 0, OES_HALF_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET); POLYGON_VERTICES_DATA_POS_OFFSET);
} else { } else {
GLES20.glVertexAttribPointer(gPolygonVertexPositionHandle, 2, glVertexAttribPointer(gPolygonVertexPositionHandle, 2,
GLES20.GL_FLOAT, false, 0, GL_FLOAT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET); POLYGON_VERTICES_DATA_POS_OFFSET);
}
// glBindBuffer(GL_ARRAY_BUFFER, 0);
} }
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
setMatrix(tile, diff); setMatrix(tile, diff);
GLES20.glUniformMatrix4fv(gPolygonMatrixHandle, 1, false, mMVPMatrix, 0); glUniformMatrix4fv(gPolygonMatrixHandle, 1, false, mMVPMatrix, 0);
MeshLayer[] layers = tile.meshLayers.array; MeshLayer[] layers = tile.meshLayers.array;
for (int i = 0, n = layers.length; i < n; i++) { for (int i = 0, n = layers.length; i < n; i++) {
MeshLayer l = layers[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); // 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; return true;
} }
@ -684,30 +740,32 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (tile.lineLayers == null || tile.lineLayers.array == null) if (tile.lineLayers == null || tile.lineLayers.array == null)
return false; 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) { if (useHalfFloat) {
GLES20.glVertexAttribPointer(gLineVertexPositionHandle, 2, OES_HALF_FLOAT, glVertexAttribPointer(gLineVertexPositionHandle, 2, OES_HALF_FLOAT,
false, 8, LINE_VERTICES_DATA_POS_OFFSET); false, 8, LINE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(gLineTexturePositionHandle, 2, OES_HALF_FLOAT, glVertexAttribPointer(gLineTexturePositionHandle, 2, OES_HALF_FLOAT,
false, 8, LINE_VERTICES_DATA_TEX_OFFSET >> 1); false, 8, LINE_VERTICES_DATA_TEX_OFFSET >> 1);
} else { } else {
GLES20.glVertexAttribPointer(gLineVertexPositionHandle, 2, GLES20.GL_FLOAT, glVertexAttribPointer(gLineVertexPositionHandle, 2, GL_FLOAT,
false, 16, LINE_VERTICES_DATA_POS_OFFSET); false, 16, LINE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(gLineTexturePositionHandle, 2, GLES20.GL_FLOAT, glVertexAttribPointer(gLineTexturePositionHandle, 2, GL_FLOAT,
false, 16, LINE_VERTICES_DATA_TEX_OFFSET); false, 16, LINE_VERTICES_DATA_TEX_OFFSET);
}
// glBindBuffer(GL_ARRAY_BUFFER, 0);
} }
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
if (diff != 0) if (diff != 0)
z = (diff > 0) ? (1 << diff) : 1.0f / (1 << -diff); z = (diff > 0) ? (1 << diff) : 1.0f / (1 << -diff);
setMatrix(tile, diff); setMatrix(tile, diff);
GLES20.glUniformMatrix4fv(gLineMatrixHandle, 1, false, mMVPMatrix, 0); glUniformMatrix4fv(gLineMatrixHandle, 1, false, mMVPMatrix, 0);
LineLayer[] layers = tile.lineLayers.array; LineLayer[] layers = tile.lineLayers.array;
@ -729,42 +787,37 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
drawFixed = l.isFixed; drawFixed = l.isFixed;
if (drawOutlines) { if (drawOutlines) {
GLES20.glUniform2f(gLineModeHandle, 0, wdiv); glUniform2f(gLineModeHandle, 0, wdiv);
} else if (!drawFixed) { } else if (!drawFixed) {
GLES20.glUniform2f(gLineModeHandle, 0, wdiv * 0.98f); glUniform2f(gLineModeHandle, 0, wdiv * 0.98f);
} }
} }
if (drawFixed) { if (drawFixed) {
if (l.width < 1.0) if (l.width < 1.0)
GLES20.glUniform2f(gLineModeHandle, 0.4f, fdiv); glUniform2f(gLineModeHandle, 0.4f, fdiv);
else 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) { if (drawOutlines) {
for (int j = 0, m = l.outlines.size(); j < m; j++) { for (int j = 0, m = l.outlines.size(); j < m; j++) {
LineLayer o = l.outlines.get(j); LineLayer o = l.outlines.get(j);
if (mSimpleLines) 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 { else {
if (mSimpleLines) 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; return true;
} }
@ -940,47 +993,53 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
} }
private boolean mTriangulate = false;
private int uploadCnt = 0; private int uploadCnt = 0;
private boolean uploadTileData(GLMapTile tile) { 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) // double start = SystemClock.uptimeMillis();
GLES20.glFinish();
// 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) { if (tile.lineVBO == null) {
// Upload line data to vertex buffer object
synchronized (mVBOs) { synchronized (mVBOs) {
if (mVBOs.size() < 2) if (mVBOs.size() < 2) {
Log.d(TAG, "uploadTileData, no VBOs left");
return false; return false;
}
tile.lineVBO = mVBOs.remove(mVBOs.size() - 1); tile.lineVBO = mVBOs.remove(mVBOs.size() - 1);
tile.polygonVBO = mVBOs.remove(mVBOs.size() - 1); tile.polygonVBO = mVBOs.remove(mVBOs.size() - 1);
} }
} }
if (useHalfFloat) if (useHalfFloat)
shortBuffer = tile.lineLayers.compileLayerData(shortBuffer); shortBuffer[uploadCnt * 2] = tile.lineLayers
.compileLayerData(shortBuffer[uploadCnt * 2]);
else else
floatBuffer = tile.lineLayers.compileLayerData(floatBuffer); floatBuffer[uploadCnt * 2] = tile.lineLayers
.compileLayerData(floatBuffer[uploadCnt * 2]);
if (tile.lineLayers.size > 0) { if (tile.lineLayers.size > 0) {
mBufferMemoryUsage -= tile.lineVBO.size; mBufferMemoryUsage -= tile.lineVBO.size;
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.id); glBindBuffer(GL_ARRAY_BUFFER, tile.lineVBO.id);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 0, null, GLES20.GL_STATIC_DRAW); // glBufferData(GL_ARRAY_BUFFER, 0, null, GL_DYNAMIC_DRAW);
if (useHalfFloat) { if (useHalfFloat) {
tile.lineVBO.size = tile.lineLayers.size * SHORT_BYTES; tile.lineVBO.size = tile.lineLayers.size * SHORT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.size, glBufferData(GL_ARRAY_BUFFER, tile.lineVBO.size,
shortBuffer, GLES20.GL_STATIC_DRAW); shortBuffer[uploadCnt * 2], GL_DYNAMIC_DRAW);
} else { } else {
tile.lineVBO.size = tile.lineLayers.size * FLOAT_BYTES; tile.lineVBO.size = tile.lineLayers.size * FLOAT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.lineVBO.size, glBufferData(GL_ARRAY_BUFFER, tile.lineVBO.size,
floatBuffer, GLES20.GL_STATIC_DRAW); floatBuffer[uploadCnt * 2], GL_DYNAMIC_DRAW);
} }
mBufferMemoryUsage += tile.lineVBO.size; mBufferMemoryUsage += tile.lineVBO.size;
@ -991,26 +1050,28 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (!mTriangulate) { if (!mTriangulate) {
if (useHalfFloat) if (useHalfFloat)
shortBuffer = tile.polygonLayers.compileLayerData(shortBuffer); shortBuffer[uploadCnt * 2 + 1] = tile.polygonLayers
.compileLayerData(shortBuffer[uploadCnt * 2 + 1]);
else else
floatBuffer = tile.polygonLayers.compileLayerData(floatBuffer); floatBuffer[uploadCnt * 2 + 1] = tile.polygonLayers
.compileLayerData(floatBuffer[uploadCnt * 2 + 1]);
// Upload polygon data to vertex buffer object // Upload polygon data to vertex buffer object
if (tile.polygonLayers.size > 0) { if (tile.polygonLayers.size > 0) {
mBufferMemoryUsage -= tile.polygonVBO.size; mBufferMemoryUsage -= tile.polygonVBO.size;
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.id); glBindBuffer(GL_ARRAY_BUFFER, tile.polygonVBO.id);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 0, null, // glBufferData(GL_ARRAY_BUFFER, 0, null,
GLES20.GL_STATIC_DRAW); // GL_DYNAMIC_DRAW);
if (useHalfFloat) { if (useHalfFloat) {
tile.polygonVBO.size = tile.polygonLayers.size * SHORT_BYTES; tile.polygonVBO.size = tile.polygonLayers.size * SHORT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size, glBufferData(GL_ARRAY_BUFFER, tile.polygonVBO.size,
shortBuffer, GLES20.GL_STATIC_DRAW); shortBuffer[uploadCnt * 2 + 1], GL_DYNAMIC_DRAW);
} else { } else {
tile.polygonVBO.size = tile.polygonLayers.size * FLOAT_BYTES; tile.polygonVBO.size = tile.polygonLayers.size * FLOAT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size, glBufferData(GL_ARRAY_BUFFER, tile.polygonVBO.size,
floatBuffer, GLES20.GL_STATIC_DRAW); floatBuffer[uploadCnt * 2 + 1], GL_DYNAMIC_DRAW);
} }
mBufferMemoryUsage += tile.polygonVBO.size; mBufferMemoryUsage += tile.polygonVBO.size;
@ -1020,26 +1081,28 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
else { else {
if (useHalfFloat) if (useHalfFloat)
shortBuffer = tile.meshLayers.compileLayerData(shortBuffer); shortBuffer[uploadCnt * 2 + 1] = tile.meshLayers
.compileLayerData(shortBuffer[uploadCnt * 2 + 1]);
else else
floatBuffer = tile.meshLayers.compileLayerData(floatBuffer); floatBuffer[uploadCnt * 2 + 1] = tile.meshLayers
.compileLayerData(floatBuffer[uploadCnt * 2 + 1]);
// Upload triangle data to vertex buffer object // Upload triangle data to vertex buffer object
if (tile.meshLayers.size > 0) { if (tile.meshLayers.size > 0) {
mBufferMemoryUsage -= tile.polygonVBO.size; mBufferMemoryUsage -= tile.polygonVBO.size;
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.id); glBindBuffer(GL_ARRAY_BUFFER, tile.polygonVBO.id);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 0, null, // glBufferData(GL_ARRAY_BUFFER, 0, null,
GLES20.GL_STATIC_DRAW); // GL_DYNAMIC_DRAW);
if (useHalfFloat) { if (useHalfFloat) {
tile.polygonVBO.size = tile.meshLayers.size * SHORT_BYTES; tile.polygonVBO.size = tile.meshLayers.size * SHORT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size, glBufferData(GL_ARRAY_BUFFER, tile.polygonVBO.size,
shortBuffer, GLES20.GL_STATIC_DRAW); shortBuffer[uploadCnt * 2 + 1], GL_DYNAMIC_DRAW);
} else { } else {
tile.polygonVBO.size = tile.meshLayers.size * FLOAT_BYTES; tile.polygonVBO.size = tile.meshLayers.size * FLOAT_BYTES;
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, tile.polygonVBO.size, glBufferData(GL_ARRAY_BUFFER, tile.polygonVBO.size,
floatBuffer, GLES20.GL_STATIC_DRAW); floatBuffer[uploadCnt * 2 + 1], GL_DYNAMIC_DRAW);
} }
mBufferMemoryUsage += tile.polygonVBO.size; mBufferMemoryUsage += tile.polygonVBO.size;
@ -1050,6 +1113,13 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
tile.newData = false; tile.newData = false;
tile.isDrawn = true; tile.isDrawn = true;
tile.isLoading = false; 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; return true;
} }
@ -1066,10 +1136,9 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (timing) if (timing)
start = SystemClock.uptimeMillis(); start = SystemClock.uptimeMillis();
GLES20.glStencilMask(0xFF); glStencilMask(0xFF);
GLES20.glDisable(GLES20.GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// GLES20.glFlush();
// long endTime = SystemClock.uptimeMillis(); // long endTime = SystemClock.uptimeMillis();
// long dt = endTime - startTime; // long dt = endTime - startTime;
@ -1100,22 +1169,21 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
GLMapTile[] tiles = curTiles.tiles; GLMapTile[] tiles = curTiles.tiles;
if (mBufferMemoryUsage > LIMIT_BUFFERS) { if (mBufferMemoryUsage > LIMIT_BUFFERS) {
Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / (1024 * 1024) Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / MB + "MB");
+ "MB");
synchronized (mVBOs) { synchronized (mVBOs) {
for (VertexBufferObject vbo : mVBOs) { for (VertexBufferObject vbo : mVBOs) {
if (vbo.size == 0) if (vbo.size == 0)
continue; continue;
mBufferMemoryUsage -= vbo.size; mBufferMemoryUsage -= vbo.size;
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo.id); glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 0, null, glBufferData(GL_ARRAY_BUFFER, 0, null,
GLES20.GL_STATIC_DRAW); GL_DYNAMIC_DRAW);
vbo.size = 0; 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) if (CACHE_TILES > 50)
CACHE_TILES -= 50; CACHE_TILES -= 50;
@ -1124,6 +1192,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
uploadCnt = 0; uploadCnt = 0;
mLastBoundVBO = -1;
// check visible tiles, set tile clip scissors, upload new vertex data // check visible tiles, set tile clip scissors, upload new vertex data
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
@ -1134,11 +1203,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (tile.newData) { if (tile.newData) {
uploadTileData(tile); uploadTileData(tile);
if (timing)
Log.d(TAG, "buffer upload took: "
+ (SystemClock.uptimeMillis() - start));
continue; 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) if (timing)
clear_time = (SystemClock.uptimeMillis() - start); clear_time = (SystemClock.uptimeMillis() - start);
GLES20.glEnable(GLES20.GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
GLES20.glUseProgram(gPolygonProgram); glUseProgram(gPolygonProgram);
// GLES20.glEnableVertexAttribArray(gPolygonVertexPositionHandle); glEnableVertexAttribArray(gPolygonVertexPositionHandle);
if (!mTriangulate) { if (!mTriangulate) {
GLES20.glDisable(GLES20.GL_BLEND); glDisable(GL_BLEND);
// Draw Polygons // Draw Polygons
GLES20.glEnable(GLES20.GL_STENCIL_TEST); glEnable(GL_STENCIL_TEST);
// GLES20.glEnableVertexAttribArray(gPolygonVertexPositionHandle); // glEnableVertexAttribArray(gPolygonVertexPositionHandle);
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
if (tiles[i].isVisible) { if (tiles[i].isVisible) {
@ -1186,8 +1252,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
drawProxyPolygons(tile); drawProxyPolygons(tile);
} }
} }
GlUtils.checkGlError("polygons"); // GlUtils.checkGlError("polygons");
GLES20.glDisable(GLES20.GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
} else { } else {
// Draw Triangles // Draw Triangles
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
@ -1200,23 +1266,22 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
drawProxyTriangles(tile); drawProxyTriangles(tile);
} }
} }
GlUtils.checkGlError("triangles"); // GlUtils.checkGlError("triangles");
} }
// required on GalaxyII, Android 2.3.3 // required on GalaxyII, Android 2.3.3 (cant just VAA enable once...)
// GLES20.glDisableVertexAttribArray(gPolygonVertexPositionHandle); glDisableVertexAttribArray(gPolygonVertexPositionHandle);
if (timing) { if (timing) {
GLES20.glFinish(); glFinish();
poly_time = (SystemClock.uptimeMillis() - start); poly_time = (SystemClock.uptimeMillis() - start);
} }
GLES20.glFlush();
// Draw lines // Draw lines
GLES20.glEnable(GLES20.GL_BLEND); glEnable(GL_BLEND);
GLES20.glUseProgram(gLineProgram); glUseProgram(gLineProgram);
// GLES20.glEnableVertexAttribArray(gLineVertexPositionHandle); glEnableVertexAttribArray(gLineVertexPositionHandle);
// GLES20.glEnableVertexAttribArray(gLineTexturePositionHandle); glEnableVertexAttribArray(gLineTexturePositionHandle);
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
if (tiles[i].isVisible) { if (tiles[i].isVisible) {
@ -1230,14 +1295,13 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
if (timing) { if (timing) {
GLES20.glFinish(); glFinish();
Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start) + " " Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start) + " "
+ clear_time + " " + poly_time); + clear_time + " " + poly_time);
} }
// GLES20.glDisableVertexAttribArray(gLineVertexPositionHandle); glDisableVertexAttribArray(gLineVertexPositionHandle);
// GLES20.glDisableVertexAttribArray(gLineTexturePositionHandle); glDisableVertexAttribArray(gLineTexturePositionHandle);
GlUtils.checkGlError("lines"); // GlUtils.checkGlError("lines");
GLES20.glFinish();
} }
private int[] mVboIds; private int[] mVboIds;
@ -1261,7 +1325,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
mHeight = height; mHeight = height;
mAspect = (float) height / width; 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); int tiles = (mWidth / Tile.TILE_SIZE + 4) * (mHeight / Tile.TILE_SIZE + 4);
curTiles = new TilesData(tiles); curTiles = new TilesData(tiles);
@ -1271,7 +1335,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
// Set up vertex buffer objects // Set up vertex buffer objects
int numVBO = (CACHE_TILES + tiles) * 2; int numVBO = (CACHE_TILES + tiles) * 2;
mVboIds = new int[numVBO]; mVboIds = new int[numVBO];
GLES20.glGenBuffers(numVBO, mVboIds, 0); glGenBuffers(numVBO, mVboIds, 0);
for (int i = 0; i < numVBO; i++) for (int i = 0; i < numVBO; i++)
mVBOs.add(new VertexBufferObject(mVboIds[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; useHalfFloat = true;
shortBuffer = new ShortBuffer[20];
}
else {
floatBuffer = new FloatBuffer[20];
}
Log.d(TAG, "Extensions: " + ext); Log.d(TAG, "Extensions: " + ext);
gLineMatrixHandle = GLES20.glGetUniformLocation(gLineProgram, "u_center"); gLineMatrixHandle = glGetUniformLocation(gLineProgram, "u_center");
gLineModeHandle = GLES20.glGetUniformLocation(gLineProgram, "u_mode"); gLineModeHandle = glGetUniformLocation(gLineProgram, "u_mode");
gLineColorHandle = GLES20.glGetUniformLocation(gLineProgram, "u_color"); gLineColorHandle = glGetUniformLocation(gLineProgram, "u_color");
gLineVertexPositionHandle = GLES20 gLineVertexPositionHandle = GLES20
.glGetAttribLocation(gLineProgram, "a_position"); .glGetAttribLocation(gLineProgram, "a_position");
gLineTexturePositionHandle = GLES20.glGetAttribLocation(gLineProgram, "a_st"); gLineTexturePositionHandle = glGetAttribLocation(gLineProgram, "a_st");
if (mSimpleLines) if (mSimpleLines)
gLineWidthHandle = GLES20.glGetUniformLocation(gLineProgram, "u_width"); gLineWidthHandle = glGetUniformLocation(gLineProgram, "u_width");
// Set up the program for rendering polygons // Set up the program for rendering polygons
gPolygonProgram = GlUtils.createProgram(Shaders.gPolygonVertexShader, 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."); Log.e(TAG, "Could not create polygon program.");
return; return;
} }
gPolygonMatrixHandle = GLES20.glGetUniformLocation(gPolygonProgram, "u_center"); gPolygonMatrixHandle = glGetUniformLocation(gPolygonProgram, "u_center");
gPolygonVertexPositionHandle = GLES20.glGetAttribLocation(gPolygonProgram, gPolygonVertexPositionHandle = glGetAttribLocation(gPolygonProgram,
"a_position"); "a_position");
gPolygonColorHandle = GLES20.glGetUniformLocation(gPolygonProgram, "u_color"); gPolygonColorHandle = glGetUniformLocation(gPolygonProgram, "u_color");
GLES20.glUseProgram(gPolygonProgram); // glUseProgram(gPolygonProgram);
GLES20.glEnableVertexAttribArray(gPolygonVertexPositionHandle); // glEnableVertexAttribArray(gPolygonVertexPositionHandle);
//
// glUseProgram(gLineProgram);
// glEnableVertexAttribArray(gLineVertexPositionHandle);
// glEnableVertexAttribArray(gLineTexturePositionHandle);
GLES20.glUseProgram(gLineProgram); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLES20.glEnableVertexAttribArray(gLineVertexPositionHandle);
GLES20.glEnableVertexAttribArray(gLineTexturePositionHandle);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_DEPTH_TEST);
glDepthMask(false);
GLES20.glDisable(GLES20.GL_DEPTH_TEST); glDisable(GL_DITHER);
GLES20.glDepthMask(false); glClearColor(0.98f, 0.98f, 0.97f, 1.0f);
GLES20.glDisable(GLES20.GL_DITHER); glClearStencil(0);
GLES20.glClearColor(0.98f, 0.98f, 0.97f, 1.0f);
GLES20.glClearStencil(0);
// GLES20.glFrontFace(GLES20.GL_CCW);
} }
@Override @Override
public boolean processedTile() { public boolean processedTile() {
return true; 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); // Log.d("GLMap", "allocate buffer " + size);
fbuf = bbuf.asFloatBuffer(); fbuf = bbuf.asFloatBuffer();
} else { } else {
fbuf.position(0); fbuf.clear();
} }
fbuf.put(mFillCoords, 0, 8); fbuf.put(mFillCoords, 0, 8);
@ -95,7 +95,7 @@ class PolygonLayers {
l.pool = null; l.pool = null;
} }
fbuf.position(0); fbuf.flip();
// not needed for drawing // not needed for drawing
layers = null; layers = null;
@ -121,7 +121,7 @@ class PolygonLayers {
ByteOrder.nativeOrder()); ByteOrder.nativeOrder());
sbuf = bbuf.asShortBuffer(); sbuf = bbuf.asShortBuffer();
} else { } else {
sbuf.position(0); sbuf.clear();
} }
short[] data = new short[PoolItem.SIZE]; short[] data = new short[PoolItem.SIZE];
@ -157,7 +157,7 @@ class PolygonLayers {
l.pool = null; l.pool = null;
} }
sbuf.position(0); sbuf.flip();
// not needed for drawing // not needed for drawing
layers = null; layers = null;

View File

@ -14,9 +14,7 @@
*/ */
package org.mapsforge.android.mapgenerator; package org.mapsforge.android.mapgenerator;
import org.mapsforge.android.MapRenderer; import org.mapsforge.android.rendertheme.RenderTheme;
import org.mapsforge.android.MapView;
import org.mapsforge.core.GeoPoint;
import org.mapsforge.database.IMapDatabase; import org.mapsforge.database.IMapDatabase;
/** /**
@ -37,31 +35,13 @@ public interface IMapGenerator {
*/ */
boolean executeJob(MapGeneratorJob mapGeneratorJob); 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 * @param mapDatabase
* the MapDatabase from which the map data will be read. * the MapDatabase from which the map data will be read.
*/ */
void setMapDatabase(IMapDatabase mapDatabase); 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. * 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. * The text scale factor which should applied to the render theme.
@ -32,13 +32,13 @@ public class JobParameters {
private final int mHashCodeValue; private final int mHashCodeValue;
/** /**
* @param jobTheme * @param theme
* render theme which should be used. * render theme which should be used.
* @param textScale * @param textScale
* the text scale factor which should applied to the render theme. * the text scale factor which should applied to the render theme.
*/ */
public JobParameters(JobTheme jobTheme, float textScale) { public JobParameters(Theme theme, float textScale) {
this.jobTheme = jobTheme; this.theme = theme;
this.textScale = textScale; this.textScale = textScale;
mHashCodeValue = calculateHashCode(); mHashCodeValue = calculateHashCode();
} }
@ -52,11 +52,11 @@ public class JobParameters {
return false; return false;
} }
JobParameters other = (JobParameters) obj; JobParameters other = (JobParameters) obj;
if (jobTheme == null) { if (theme == null) {
if (other.jobTheme != null) { if (other.theme != null) {
return false; return false;
} }
} else if (!jobTheme.equals(other.jobTheme)) { } else if (!theme.equals(other.theme)) {
return false; return false;
} }
if (Float.floatToIntBits(textScale) != Float.floatToIntBits(other.textScale)) { if (Float.floatToIntBits(textScale) != Float.floatToIntBits(other.textScale)) {
@ -75,7 +75,7 @@ public class JobParameters {
*/ */
private int calculateHashCode() { private int calculateHashCode() {
int result = 7; 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); result = 31 * result + Float.floatToIntBits(textScale);
return result; return result;
} }

View File

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

View File

@ -37,29 +37,40 @@ public final class MapDatabaseFactory {
return new org.mapsforge.database.postgis.MapDatabase(); return new org.mapsforge.database.postgis.MapDatabase();
} }
MapDatabaseInternal mapDatabaseInternal = MapDatabaseInternal MapDatabases mapDatabaseInternal = MapDatabases.valueOf(mapDatabaseName);
.valueOf(mapDatabaseName);
return MapDatabaseFactory.createMapDatabase(mapDatabaseInternal); 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. * the internal MapDatabase implementation.
* @return a new MapGenerator instance. * @return a new MapGenerator instance.
*/ */
public static IMapDatabase createMapDatabase(MapDatabaseInternal mapDatabaseInternal) { public static IMapDatabase createMapDatabase(MapDatabases mapDatabase) {
switch (mapDatabaseInternal) { switch (mapDatabase) {
case MAP_READER: case MAP_READER:
return new org.mapsforge.database.mapfile.MapDatabase(); return new org.mapsforge.database.mapfile.MapDatabase();
case JSON_READER: case JSON_READER:
return new org.mapsforge.database.json.MapDatabase(); return new org.mapsforge.database.json.MapDatabase();
case POSTGIS_READER: case POSTGIS_READER:
return new org.mapsforge.database.postgis.MapDatabase(); 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() { private MapDatabaseFactory() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@ import java.io.Serializable;
/** /**
* A JobTheme defines the render theme which is used for a {@link MapGeneratorJob}. * 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. * @return an InputStream to read the render theme data from.
* @throws FileNotFoundException * @throws FileNotFoundException

View File

@ -21,12 +21,12 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.ObjectInputStream; 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. * 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 static final long serialVersionUID = 1L;
private final long mFileModificationDate; private final long mFileModificationDate;

View File

@ -16,12 +16,12 @@ package org.mapsforge.android.rendertheme;
import java.io.InputStream; import java.io.InputStream;
import org.mapsforge.android.mapgenerator.JobTheme; import org.mapsforge.android.mapgenerator.Theme;
/** /**
* Enumeration of all internal rendering themes. * 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. * A rendering theme similar to the OpenStreetMap Osmarender style.
* *
@ -37,6 +37,9 @@ public enum InternalRenderTheme implements JobTheme {
@Override @Override
public InputStream getRenderThemeAsStream() { 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[]> mMatchingCacheWay;
private final LRUCache<MatchingCacheKey, RenderInstruction[]> mMatchingCacheArea; 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) { RenderTheme(int mapBackground, float baseStrokeWidth, float baseTextSize) {
mMapBackground = mapBackground; mMapBackground = mapBackground;
mBaseStrokeWidth = baseStrokeWidth; 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. * Matches a way with the given parameters against this RenderTheme.
@ -213,23 +209,26 @@ public class RenderTheme {
* way is Closed * way is Closed
* @param changed * @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) { boolean closed, boolean changed) {
RenderInstruction[] renderInstructions = null; RenderInstruction[] renderInstructions = null;
LRUCache<MatchingCacheKey, RenderInstruction[]> matchingCache; LRUCache<MatchingCacheKey, RenderInstruction[]> matchingCache;
MatchingCacheKey matchingCacheKey; MatchingCacheKey matchingCacheKey;
if (!changed) { // if (!changed) {
renderInstructions = mRenderInstructions; // renderInstructions = mRenderInstructions;
//
if (renderInstructions != null) { // if (renderInstructions != null) {
for (int i = 0, n = renderInstructions.length; i < n; i++) // for (int i = 0, n = renderInstructions.length; i < n; i++)
renderInstructions[i].renderWay(renderCallback, tags); // renderInstructions[i].renderWay(renderCallback, tags);
} // }
return; // return;
} // }
if (closed) { if (closed) {
matchingCache = mMatchingCacheArea; matchingCache = mMatchingCacheArea;
@ -267,90 +266,8 @@ public class RenderTheme {
matchingCache.put(matchingCacheKey, renderInstructions); matchingCache.put(matchingCacheKey, renderInstructions);
} }
mRenderInstructions = renderInstructions; // mRenderInstructions = renderInstructions;
return 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);
} }
void addRule(Rule rule) { 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; package org.mapsforge.android.swrenderer;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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.IMapGenerator;
import org.mapsforge.android.mapgenerator.JobTheme;
import org.mapsforge.android.mapgenerator.MapGeneratorJob; import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.mapgenerator.Theme;
import org.mapsforge.android.rendertheme.IRenderCallback; import org.mapsforge.android.rendertheme.IRenderCallback;
import org.mapsforge.android.rendertheme.RenderTheme; 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.Area;
import org.mapsforge.android.rendertheme.renderinstruction.Line; import org.mapsforge.android.rendertheme.renderinstruction.Line;
import org.mapsforge.core.GeoPoint;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
import org.mapsforge.core.Tile; import org.mapsforge.core.Tile;
import org.mapsforge.database.IMapDatabase; import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.IMapDatabaseCallback; import org.mapsforge.database.IMapDatabaseCallback;
import org.mapsforge.database.MapFileInfo;
import org.mapsforge.database.mapfile.MapDatabase; import org.mapsforge.database.mapfile.MapDatabase;
import org.xml.sax.SAXException;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.util.FloatMath; import android.util.FloatMath;
import android.util.Log;
/** /**
* A DatabaseRenderer renders map tiles by reading from a {@link MapDatabase}. * A DatabaseRenderer renders map tiles by reading from a {@link MapDatabase}.
*/ */
public class DatabaseRenderer implements IMapGenerator, IRenderCallback, public class MapGenerator implements IMapGenerator, IRenderCallback,
IMapDatabaseCallback { IMapDatabaseCallback {
private static String TAG = DatabaseRenderer.class.getName(); // private static String TAG = MapGenerator.class.getName();
private static final Byte DEFAULT_START_ZOOM_LEVEL = Byte.valueOf((byte) 12);
private static final byte LAYERS = 11; private static final byte LAYERS = 11;
private static final Paint PAINT_WATER_TILE_HIGHTLIGHT = new Paint( private static final Paint PAINT_WATER_TILE_HIGHTLIGHT = new Paint(
Paint.ANTI_ALIAS_FLAG); Paint.ANTI_ALIAS_FLAG);
private static final double STROKE_INCREASE = 1.5; private static final double STROKE_INCREASE = 1.5;
private static final byte STROKE_MIN_ZOOM_LEVEL = 12; 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) { private static byte getValidLayer(byte layer) {
if (layer < 0) { if (layer < 0) {
return 0; return 0;
@ -103,7 +65,7 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
private List<PointTextContainer> mNodes; private List<PointTextContainer> mNodes;
private float mPoiX; private float mPoiX;
private float mPoiY; private float mPoiY;
private JobTheme mPreviousJobTheme; private Theme mPreviousJobTheme;
private float mPreviousTextScale; private float mPreviousTextScale;
private byte mPreviousZoomLevel; private byte mPreviousZoomLevel;
private static RenderTheme renderTheme; private static RenderTheme renderTheme;
@ -138,7 +100,7 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
/** /**
* Constructs a new DatabaseRenderer. * Constructs a new DatabaseRenderer.
*/ */
public DatabaseRenderer() { public MapGenerator() {
mCanvasRasterer = new CanvasRasterer(); mCanvasRasterer = new CanvasRasterer();
mLabelPlacement = new LabelPlacement(); mLabelPlacement = new LabelPlacement();
@ -161,8 +123,8 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
@Override @Override
public void cleanup() { public void cleanup() {
mTileBitmap.recycle(); mTileBitmap.recycle();
if (DatabaseRenderer.renderTheme != null) { if (MapGenerator.renderTheme != null) {
DatabaseRenderer.renderTheme.destroy(); MapGenerator.renderTheme.destroy();
} }
} }
@ -189,30 +151,30 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
// mTileHeight = mLat1 - mLat2; // mTileHeight = mLat1 - mLat2;
mScale = mapGeneratorJob.getScale(); mScale = mapGeneratorJob.getScale();
JobTheme jobTheme = mapGeneratorJob.jobParameters.jobTheme; // Theme theme = mapGeneratorJob.jobParameters.theme;
if (!jobTheme.equals(mPreviousJobTheme)) { // if (!theme.equals(mPreviousJobTheme)) {
if (DatabaseRenderer.renderTheme == null) // // if (MapGenerator.renderTheme == null)
DatabaseRenderer.renderTheme = getRenderTheme(jobTheme); // // MapGenerator.renderTheme = getRenderTheme(theme);
if (DatabaseRenderer.renderTheme == null) { // // if (MapGenerator.renderTheme == null) {
mPreviousJobTheme = null; // // mPreviousJobTheme = null;
return false; // // return false;
} // // }
createWayLists(); // createWayLists();
mPreviousJobTheme = jobTheme; // mPreviousJobTheme = theme;
mPreviousZoomLevel = Byte.MIN_VALUE; // mPreviousZoomLevel = Byte.MIN_VALUE;
} // }
//
byte zoomLevel = mCurrentTile.zoomLevel; // byte zoomLevel = mCurrentTile.zoomLevel;
if (zoomLevel != mPreviousZoomLevel) { // if (zoomLevel != mPreviousZoomLevel) {
setScaleStrokeWidth(zoomLevel); // setScaleStrokeWidth(zoomLevel);
mPreviousZoomLevel = zoomLevel; // mPreviousZoomLevel = zoomLevel;
} // }
//
float textScale = mapGeneratorJob.jobParameters.textScale; // float textScale = mapGeneratorJob.jobParameters.textScale;
if (textScale != mPreviousTextScale) { // if (textScale != mPreviousTextScale) {
DatabaseRenderer.renderTheme.scaleTextSize(textScale); // MapGenerator.renderTheme.scaleTextSize(textScale);
mPreviousTextScale = textScale; // mPreviousTextScale = textScale;
} // }
if (mMapDatabase != null) { if (mMapDatabase != null) {
mMapDatabase.executeQuery(mCurrentTile, this); mMapDatabase.executeQuery(mCurrentTile, this);
@ -230,7 +192,7 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
// FIXME mCoords = mMapDatabase.getCoordinates(); // FIXME mCoords = mMapDatabase.getCoordinates();
mCanvasRasterer.setCanvasBitmap(mTileBitmap, mScale); mCanvasRasterer.setCanvasBitmap(mTileBitmap, mScale);
mCanvasRasterer.fill(DatabaseRenderer.renderTheme.getMapBackground()); mCanvasRasterer.fill(MapGenerator.renderTheme.getMapBackground());
mCanvasRasterer.drawWays(mCoords, mWays); mCanvasRasterer.drawWays(mCoords, mWays);
mCanvasRasterer.drawSymbols(mWaySymbols); mCanvasRasterer.drawSymbols(mWaySymbols);
mCanvasRasterer.drawSymbols(mPointSymbols); mCanvasRasterer.drawSymbols(mPointSymbols);
@ -255,37 +217,6 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
return true; 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 @Override
public void renderAreaCaption(String textKey, float verticalOffset, Paint paint, public void renderAreaCaption(String textKey, float verticalOffset, Paint paint,
Paint stroke) { Paint stroke) {
@ -314,7 +245,7 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
mDrawingLayer = mWays[getValidLayer(layer)]; mDrawingLayer = mWays[getValidLayer(layer)];
mPoiX = scaleLongitude(longitude); mPoiX = scaleLongitude(longitude);
mPoiY = scaleLatitude(latitude); mPoiY = scaleLatitude(latitude);
DatabaseRenderer.renderTheme.matchNode(this, tags, mCurrentTile.zoomLevel); MapGenerator.renderTheme.matchNode(this, tags, mCurrentTile.zoomLevel);
} }
@Override @Override
@ -539,7 +470,7 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
} }
private void createWayLists() { private void createWayLists() {
int levels = DatabaseRenderer.renderTheme.getLevels(); int levels = MapGenerator.renderTheme.getLevels();
for (byte i = LAYERS - 1; i >= 0; --i) { for (byte i = LAYERS - 1; i >= 0; --i) {
mWays[i] = new LayerContainer(levels); mWays[i] = new LayerContainer(levels);
} }
@ -581,12 +512,18 @@ public class DatabaseRenderer implements IMapGenerator, IRenderCallback,
*/ */
private static void setScaleStrokeWidth(byte zoomLevel) { private static void setScaleStrokeWidth(byte zoomLevel) {
int zoomLevelDiff = Math.max(zoomLevel - STROKE_MIN_ZOOM_LEVEL, 0); 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)); zoomLevelDiff));
} }
@Override @Override
public MapRenderer getMapRenderer(MapView mapView) { public IMapDatabase getMapDatabase() {
return new MapRenderer(mapView); 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.DebugSettings;
import org.mapsforge.android.MapView; import org.mapsforge.android.MapView;
import org.mapsforge.android.mapgenerator.JobParameters;
import org.mapsforge.android.mapgenerator.IMapGenerator; import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.JobParameters;
import org.mapsforge.android.mapgenerator.MapGeneratorJob; import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.mapgenerator.MapWorker;
import org.mapsforge.android.mapgenerator.TileCacheKey; import org.mapsforge.android.mapgenerator.TileCacheKey;
import org.mapsforge.android.mapgenerator.TileDistanceSort; import org.mapsforge.android.mapgenerator.TileDistanceSort;
import org.mapsforge.android.utils.GlUtils; 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 String TAG = "MapRenderer";
private static final int FLOAT_SIZE_BYTES = 4; private static final int FLOAT_SIZE_BYTES = 4;
@ -72,7 +71,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
private ArrayList<MapGeneratorJob> mJobList; private ArrayList<MapGeneratorJob> mJobList;
ArrayList<Integer> mTextures; ArrayList<Integer> mTextures;
MapWorker mMapWorker;
MapView mMapView; MapView mMapView;
GLMapTile[] currentTiles; GLMapTile[] currentTiles;
@ -97,7 +95,6 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
*/ */
public MapRenderer(MapView mapView) { public MapRenderer(MapView mapView) {
mMapView = mapView; mMapView = mapView;
mMapWorker = mapView.getMapWorker();
mDebugSettings = mapView.getDebugSettings(); mDebugSettings = mapView.getDebugSettings();
mMapScale = 1; mMapScale = 1;
@ -133,7 +130,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
if (diff != 0) if (diff != 0)
{ {
float z = (diff > 0) ? (1 << diff) : 1.0f / (1 << -diff); 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; t.distance *= 2 * diff * diff;
} else { } else {
t.distance = (Math.abs(t.tileX - x) + Math.abs(t.tileY - y)); 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()) { if (t.hasTexture()) {
synchronized (mTextures) { 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(); mJobList.clear();
IMapGenerator mapGenerator = mMapView.getMapGenerator(); // IMapGenerator mapGenerator = mMapView.getMapGenerator();
int tiles = 0; int tiles = 0;
for (long tileY = tileTop - 1; tileY <= tileBottom + 1; tileY++) { for (long tileY = tileTop - 1; tileY <= tileBottom + 1; tileY++) {
for (long tileX = tileLeft - 1; tileX <= tileRight + 1; tileX++) { 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)) { if (!tile.isDrawn || (tile.getScale() != scale)) {
tile.isLoading = true; tile.isLoading = true;
// approximation for TileScheduler // approximation for TileScheduler
if (tileY < tileTop || tileY > tileBottom || tileX < tileLeft || tileX > tileRight) if (tileY < tileTop || tileY > tileBottom || tileX < tileLeft
|| tileX > tileRight)
tile.isVisible = false; tile.isVisible = false;
else else
tile.isVisible = true; tile.isVisible = true;
MapGeneratorJob job = new MapGeneratorJob(tile, mapGenerator, MapGeneratorJob job = new MapGeneratorJob(tile, mJobParameter,
mJobParameter, mDebugSettings); mDebugSettings);
job.setScale(scale); job.setScale(scale);
mJobList.add(job); mJobList.add(job);
} }
@ -243,10 +243,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
if (mJobList.size() > 0) { if (mJobList.size() > 0) {
mMapView.getJobQueue().setJobs(mJobList); mMapView.addJobs(mJobList);
synchronized (mMapWorker) {
mMapWorker.notify();
}
} }
return true; return true;
@ -262,10 +259,12 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
mMapPosition = mMapView.getMapPosition().getMapPosition(); mMapPosition = mMapView.getMapPosition().getMapPosition();
long x = (long) MercatorProjection.longitudeToPixelX(mMapPosition.geoPoint.getLongitude(), long x = (long) MercatorProjection.longitudeToPixelX(
mMapPosition.geoPoint.getLongitude(),
mMapPosition.zoomLevel); mMapPosition.zoomLevel);
long y = (long) MercatorProjection long y = (long) MercatorProjection
.latitudeToPixelY(mMapPosition.geoPoint.getLatitude(), mMapPosition.zoomLevel); .latitudeToPixelY(mMapPosition.geoPoint.getLatitude(),
mMapPosition.zoomLevel);
long tileX = MercatorProjection.pixelXToTileX(x, mMapPosition.zoomLevel); long tileX = MercatorProjection.pixelXToTileX(x, mMapPosition.zoomLevel);
long tileY = MercatorProjection.pixelYToTileY(y, 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); z = 1.0f / (1 << -diff);
} }
drawX = MercatorProjection drawX = MercatorProjection
.longitudeToPixelX(mMapPosition.geoPoint.getLongitude(), tile.zoomLevel); .longitudeToPixelX(mMapPosition.geoPoint.getLongitude(),
tile.zoomLevel);
drawY = MercatorProjection drawY = MercatorProjection
.latitudeToPixelY(mMapPosition.geoPoint.getLatitude(), tile.zoomLevel); .latitudeToPixelY(mMapPosition.geoPoint.getLatitude(), tile.zoomLevel);
@ -377,7 +377,8 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
Matrix.setIdentityM(mMatrix, 0); Matrix.setIdentityM(mMatrix, 0);
// map tile GL coordinates to screen coordinates // 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 // scale tile
Matrix.scaleM(mMatrix, 0, mapScale / z, mapScale / z, 1); Matrix.scaleM(mMatrix, 0, mapScale / z, mapScale / z, 1);
@ -396,7 +397,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
@Override @Override
public void onDrawFrame(GL10 glUnused) { public void onDrawFrame(GL10 glUnused) {
boolean loadedTexture = false; // boolean loadedTexture = false;
GLES20.glDisable(GLES20.GL_SCISSOR_TEST); GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
GLES20.glClearColor(0.95f, 0.95f, 0.94f, 1.0f); GLES20.glClearColor(0.95f, 0.95f, 0.94f, 1.0f);
// GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); // 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) { if (tile.getTexture() >= 0) {
// reuse tile texture // reuse tile texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tile.getTexture()); 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) { } else if (mTextures.size() > 0) {
// reuse texture from previous tiles // reuse texture from previous tiles
Integer texture; Integer texture;
texture = mTextures.remove(mTextures.size() - 1); texture = mTextures.remove(mTextures.size() - 1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture.intValue()); 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()); tile.setTexture(texture.intValue());
} else { } else {
// create texture // create texture
@ -457,7 +460,7 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
mMapGeneratorJob = null; mMapGeneratorJob = null;
processedTile = true; processedTile = true;
loadedTexture = true; // loadedTexture = true;
} }
int tileSize = (int) (Tile.TILE_SIZE * mMapScale); int tileSize = (int) (Tile.TILE_SIZE * mMapScale);
int hWidth = mWidth >> 1; int hWidth = mWidth >> 1;
@ -491,11 +494,12 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
} }
} }
} }
if (loadedTexture) { // FIXME
synchronized (mMapWorker) { // if (loadedTexture) {
mMapWorker.notify(); // synchronized (mMapWorker) {
} // mMapWorker.notify();
} // }
// }
} }
@Override @Override
@ -579,65 +583,9 @@ public class MapRenderer implements org.mapsforge.android.MapRenderer {
public boolean processedTile() { public boolean processedTile() {
return 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, float[] coordinates, WayDataContainer wayDataContainer,
List<WayTextContainer> wayNames) { List<WayTextContainer> wayNames) {
@ -185,7 +185,7 @@ final class WayDecorator {
if (wayNameWidth < 0) { if (wayNameWidth < 0) {
if (text == null) { if (text == null) {
text = databaseRenderer.getWayName(); text = mapGenerator.getWayName();
if (text == null) if (text == null)
text = "blub"; text = "blub";
} }

View File

@ -40,13 +40,17 @@ public class GlUtils {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID); 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); GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
@ -125,4 +129,16 @@ public class GlUtils {
// throw new RuntimeException(op + ": glError " + error); // 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. * @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.MapActivity;
import org.mapsforge.android.MapController; import org.mapsforge.android.MapController;
import org.mapsforge.android.MapView; import org.mapsforge.android.MapView;
import org.mapsforge.android.mapgenerator.MapDatabaseFactory; import org.mapsforge.android.mapgenerator.MapDatabases;
import org.mapsforge.android.mapgenerator.MapDatabaseInternal;
import org.mapsforge.android.rendertheme.InternalRenderTheme; import org.mapsforge.android.rendertheme.InternalRenderTheme;
import org.mapsforge.android.utils.AndroidUtils; import org.mapsforge.android.utils.AndroidUtils;
import org.mapsforge.app.filefilter.FilterByFileExtension; 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.app.preferences.EditPreferences;
import org.mapsforge.core.BoundingBox; import org.mapsforge.core.BoundingBox;
import org.mapsforge.core.GeoPoint; import org.mapsforge.core.GeoPoint;
import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.MapFileInfo; import org.mapsforge.database.MapFileInfo;
import android.annotation.TargetApi; 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_MAP_FILE = 0;
private static final int SELECT_RENDER_THEME_FILE = 1; private static final int SELECT_RENDER_THEME_FILE = 1;
private LocationManager mLocationManager; private LocationManager mLocationManager;
private MapDatabaseInternal mMapDatabaseInternal; private MapDatabases mMapDatabase;
private MyLocationListener mMyLocationListener; private MyLocationListener mMyLocationListener;
private boolean mShowMyLocation; private boolean mShowMyLocation;
private boolean mSnapToLocation; private boolean mSnapToLocation;
@ -88,8 +86,11 @@ public class TileMap extends MapActivity { // implements ActionBar.OnNavigationL
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { 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; mMenu = menu;
return true; return true;
} }
@ -434,7 +435,7 @@ public class TileMap extends MapActivity { // implements ActionBar.OnNavigationL
editText.setText(Double.toString(mapCenter.getLongitude())); editText.setText(Double.toString(mapCenter.getLongitude()));
SeekBar zoomlevel = (SeekBar) dialog.findViewById(R.id.zoomLevel); 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()); zoomlevel.setProgress(mMapView.getMapPosition().getZoomLevel());
final TextView textView = (TextView) dialog.findViewById(R.id.zoomlevelValue); 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")) { if (preferences.contains("mapDatabase")) {
String name = preferences.getString("mapDatabase", String name = preferences.getString("mapDatabase",
MapDatabaseInternal.POSTGIS_READER.name()); MapDatabases.POSTGIS_READER.name());
MapDatabaseInternal mapDatabaseInternalNew; MapDatabases mapDatabaseNew;
try { try {
mapDatabaseInternalNew = MapDatabaseInternal.valueOf(name); mapDatabaseNew = MapDatabases.valueOf(name);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
mapDatabaseInternalNew = MapDatabaseInternal.POSTGIS_READER; mapDatabaseNew = MapDatabases.POSTGIS_READER;
} }
// mapDatabaseInternalNew = MapDatabaseInternal.JSON_READER; // mapDatabaseInternalNew = MapDatabaseInternal.PBMAP_READER;
Log.d("VectorTileMap", "set map database " + mapDatabaseInternalNew); Log.d("VectorTileMap", "set map database " + mapDatabaseNew);
if (mapDatabaseInternalNew != mMapDatabaseInternal) { if (mapDatabaseNew != mMapDatabase) {
IMapDatabase mapDatabase = MapDatabaseFactory mMapView.setMapDatabase(mapDatabaseNew);
.createMapDatabase(mapDatabaseInternalNew); mMapDatabase = mapDatabaseNew;
mMapView.setMapDatabase(mapDatabase);
mMapDatabaseInternal = mapDatabaseInternalNew;
} }
// if (mapDatabaseNew != mMapDatabase) {
// IMapDatabase mapDatabase = MapDatabaseFactory
// .createMapDatabase(mapDatabaseNew);
//
// mMapView.setMapDatabase(mapDatabase);
// mMapDatabase = mapDatabaseNew;
// }
} }
try { try {
@ -586,7 +593,7 @@ public class TileMap extends MapActivity { // implements ActionBar.OnNavigationL
mMapView.setDebugSettings(debugSettings); mMapView.setDebugSettings(debugSettings);
if (mMapDatabaseInternal == MapDatabaseInternal.MAP_READER) { if (mMapDatabase == MapDatabases.MAP_READER) {
if (mMapView.getMapFile() == null) if (mMapView.getMapFile() == null)
startMapFilePicker(); startMapFilePicker();
} else { } else {

View File

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

View File

@ -18,8 +18,6 @@ import org.mapsforge.app.R;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.view.WindowManager;
/** /**
* Activity to edit the application preferences. * Activity to edit the application preferences.
@ -34,16 +32,16 @@ public class EditPreferences extends PreferenceActivity {
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
getActionBar().hide(); // getActionBar().hide();
// check if the full screen mode should be activated // check if the full screen mode should be activated
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("fullscreen", // if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("fullscreen",
false)) { // false)) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); // getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); // getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
} else { // } else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); // getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_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 FileOpenResult openFile(File mapFile);
public abstract String getMapProjection();
/** /**
* @param position * @param position
* .... * ....
@ -69,4 +71,4 @@ public interface IMapDatabase {
*/ */
public abstract String readString(int position); public abstract String readString(int position);
} }

View File

@ -31,13 +31,14 @@ import org.mapsforge.database.MapFileInfo;
*/ */
public class MapDatabase implements IMapDatabase { public class MapDatabase implements IMapDatabase {
private final static String PROJECTION = "Mercator";
private float[] mCoords = new float[20]; 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("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 = private final MapFileInfo mMapInfo =
new MapFileInfo(new BoundingBox(-180, -90, 180, 90), 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; private boolean mOpenFile = false;
@ -95,10 +96,10 @@ public class MapDatabase implements IMapDatabase {
// //
// mIndex[0] = 10; // mIndex[0] = 10;
lon1 = (float) MercatorProjection.pixelXToLongitude(cx - 80, tile.zoomLevel) * 1000000; lon1 = (float) MercatorProjection.pixelXToLongitude(cx - 139, tile.zoomLevel) * 1000000;
lon2 = (float) MercatorProjection.pixelXToLongitude(cx + 80, tile.zoomLevel) * 1000000; lon2 = (float) MercatorProjection.pixelXToLongitude(cx + 139, tile.zoomLevel) * 1000000;
lat1 = (float) MercatorProjection.pixelYToLatitude(cy - 80, tile.zoomLevel) * 1000000; lat1 = (float) MercatorProjection.pixelYToLatitude(cy - 139, tile.zoomLevel) * 1000000;
lat2 = (float) MercatorProjection.pixelYToLatitude(cy + 80, tile.zoomLevel) * 1000000; lat2 = (float) MercatorProjection.pixelYToLatitude(cy + 139, tile.zoomLevel) * 1000000;
mCoords[0] = lon1; mCoords[0] = lon1;
mCoords[1] = lat1; mCoords[1] = lat1;
@ -117,9 +118,35 @@ public class MapDatabase implements IMapDatabase {
mIndex[0] = 10; 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); mapDatabaseCallback.renderWay((byte) 0, mTags, mCoords, mIndex, true);
} }
@Override
public String getMapProjection() {
return PROJECTION;
}
@Override @Override
public MapFileInfo getMapFileInfo() { public MapFileInfo getMapFileInfo() {
return mMapInfo; return mMapInfo;

View File

@ -177,11 +177,13 @@ public class MapDatabase implements IMapDatabase {
*/ */
private static final int WAY_NUMBER_OF_TAGS_BITMASK = 0x0f; 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 long mFileSize;
private boolean mDebugFile; private boolean mDebugFile;
private RandomAccessFile mInputFile; private RandomAccessFile mInputFile;
private MapFileHeader mMapFileHeader;
private ReadBuffer mReadBuffer; private ReadBuffer mReadBuffer;
private String mSignatureBlock; private String mSignatureBlock;
private String mSignaturePoi; private String mSignaturePoi;
@ -193,31 +195,6 @@ public class MapDatabase implements IMapDatabase {
private float[] mWayNodes = new float[100000]; private float[] mWayNodes = new float[100000];
private int mWayNodePosition; 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; private int minLat, minLon;
/* /*
@ -227,7 +204,7 @@ public class MapDatabase implements IMapDatabase {
*/ */
@Override @Override
public void executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) { public void executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) {
if (mMapFileHeader == null) if (sMapFileHeader == null)
return; return;
if (mIntBuffer == null) if (mIntBuffer == null)
@ -235,29 +212,13 @@ public class MapDatabase implements IMapDatabase {
mWayNodePosition = 0; 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 { try {
prepareExecution(); // prepareExecution();
QueryParameters queryParameters = new QueryParameters(); QueryParameters queryParameters = new QueryParameters();
queryParameters.queryZoomLevel = mMapFileHeader queryParameters.queryZoomLevel = sMapFileHeader
.getQueryZoomLevel(tile.zoomLevel); .getQueryZoomLevel(tile.zoomLevel);
// get and check the sub-file for the query zoom level // get and check the sub-file for the query zoom level
SubFileParameter subFileParameter = mMapFileHeader SubFileParameter subFileParameter = sMapFileHeader
.getSubFileParameter(queryParameters.queryZoomLevel); .getSubFileParameter(queryParameters.queryZoomLevel);
if (subFileParameter == null) { if (subFileParameter == null) {
LOG.warning("no sub-file for zoom level: " LOG.warning("no sub-file for zoom level: "
@ -279,10 +240,15 @@ public class MapDatabase implements IMapDatabase {
*/ */
@Override @Override
public MapFileInfo getMapFileInfo() { public MapFileInfo getMapFileInfo() {
if (mMapFileHeader == null) { if (sMapFileHeader == null) {
throw new IllegalStateException("no map file is currently opened"); 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 @Override
public FileOpenResult openFile(File mapFile) { public FileOpenResult openFile(File mapFile) {
try { try {
if (mapFile == null) { if (mapFile == null) {
// throw new IllegalArgumentException("mapFile must not be null"); // throw new IllegalArgumentException("mapFile must not be null");
@ -323,14 +290,23 @@ public class MapDatabase implements IMapDatabase {
mFileSize = mInputFile.length(); mFileSize = mInputFile.length();
mReadBuffer = new ReadBuffer(mInputFile); mReadBuffer = new ReadBuffer(mInputFile);
mMapFileHeader = new MapFileHeader(); if (instances > 0) {
FileOpenResult fileOpenResult = mMapFileHeader.readHeader(mReadBuffer, instances++;
return FileOpenResult.SUCCESS;
}
sMapFileHeader = new MapFileHeader();
FileOpenResult fileOpenResult = sMapFileHeader.readHeader(mReadBuffer,
mFileSize); mFileSize);
if (!fileOpenResult.isSuccess()) { if (!fileOpenResult.isSuccess()) {
closeFile(); closeFile();
return fileOpenResult; return fileOpenResult;
} }
prepareExecution();
instances++;
return FileOpenResult.SUCCESS; return FileOpenResult.SUCCESS;
} catch (IOException e) { } catch (IOException e) {
LOG.log(Level.SEVERE, null, 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. * Logs the debug signatures of the current way and block.
*/ */
@ -351,8 +358,8 @@ public class MapDatabase implements IMapDatabase {
} }
private void prepareExecution() { private void prepareExecution() {
if (mDatabaseIndexCache == null) { if (sDatabaseIndexCache == null) {
mDatabaseIndexCache = new IndexCache(mInputFile, INDEX_CACHE_SIZE); sDatabaseIndexCache = new IndexCache(mInputFile, INDEX_CACHE_SIZE);
} }
} }
@ -436,7 +443,7 @@ public class MapDatabase implements IMapDatabase {
long blockNumber = row * subFileParameter.blocksWidth + column; long blockNumber = row * subFileParameter.blocksWidth + column;
// get the current index entry // get the current index entry
long currentBlockIndexEntry = mDatabaseIndexCache.getIndexEntry( long currentBlockIndexEntry = sDatabaseIndexCache.getIndexEntry(
subFileParameter, blockNumber); subFileParameter, blockNumber);
// check if the current query would still return a water tile // check if the current query would still return a water tile
@ -462,7 +469,7 @@ public class MapDatabase implements IMapDatabase {
nextBlockPointer = subFileParameter.subFileSize; nextBlockPointer = subFileParameter.subFileSize;
} else { } else {
// get and check the next block pointer // get and check the next block pointer
nextBlockPointer = mDatabaseIndexCache.getIndexEntry( nextBlockPointer = sDatabaseIndexCache.getIndexEntry(
subFileParameter, blockNumber + 1) subFileParameter, blockNumber + 1)
& BITMASK_INDEX_OFFSET; & BITMASK_INDEX_OFFSET;
if (nextBlockPointer < 1 if (nextBlockPointer < 1
@ -559,7 +566,7 @@ public class MapDatabase implements IMapDatabase {
* @return true if the POIs could be processed successfully, false otherwise. * @return true if the POIs could be processed successfully, false otherwise.
*/ */
private boolean processPOIs(IMapDatabaseCallback mapDatabaseCallback, int numberOfPois) { private boolean processPOIs(IMapDatabaseCallback mapDatabaseCallback, int numberOfPois) {
Tag[] poiTags = mMapFileHeader.getMapFileInfo().poiTags; Tag[] poiTags = sMapFileHeader.getMapFileInfo().poiTags;
Tag[] tags = null; Tag[] tags = null;
for (int elementCounter = numberOfPois; elementCounter != 0; --elementCounter) { for (int elementCounter = numberOfPois; elementCounter != 0; --elementCounter) {
@ -778,7 +785,7 @@ public class MapDatabase implements IMapDatabase {
int numberOfWays) { int numberOfWays) {
Tag[] tags = null; Tag[] tags = null;
Tag[] wayTags = mMapFileHeader.getMapFileInfo().wayTags; Tag[] wayTags = sMapFileHeader.getMapFileInfo().wayTags;
int[] textPos = new int[3]; int[] textPos = new int[3];
// float[] labelPosition; // float[] labelPosition;
boolean skippedWays = false; boolean skippedWays = false;
@ -957,7 +964,7 @@ public class MapDatabase implements IMapDatabase {
|| cumulatedNumberOfWays > MAXIMUM_ZOOM_TABLE_OBJECTS) { || cumulatedNumberOfWays > MAXIMUM_ZOOM_TABLE_OBJECTS) {
LOG.warning("invalid cumulated number of ways in row " + row + ' ' LOG.warning("invalid cumulated number of ways in row " + row + ' '
+ cumulatedNumberOfWays); + cumulatedNumberOfWays);
if (mMapFileHeader.getMapFileInfo().debugFile) { if (sMapFileHeader.getMapFileInfo().debugFile) {
LOG.warning(DEBUG_SIGNATURE_BLOCK + mSignatureBlock); LOG.warning(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
} }
return null; 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.BoundingBox;
import org.mapsforge.core.GeoPoint; import org.mapsforge.core.GeoPoint;
import org.mapsforge.core.WebMercator;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
import org.mapsforge.core.Tile; import org.mapsforge.core.Tile;
import org.mapsforge.core.WebMercator;
import org.mapsforge.database.FileOpenResult; import org.mapsforge.database.FileOpenResult;
import org.mapsforge.database.IMapDatabase; import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.IMapDatabaseCallback; import org.mapsforge.database.IMapDatabaseCallback;
@ -40,7 +40,7 @@ import org.postgresql.PGConnection;
* *
*/ */
public class MapDatabase implements IMapDatabase { 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; 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 MapFileInfo(new BoundingBox(-180, -85, 180, 85),
new Byte((byte) 14), new GeoPoint(53.11, 8.85), new Byte((byte) 14), new GeoPoint(53.11, 8.85),
WebMercator.NAME, WebMercator.NAME,
0, 0, 0, "de", "yo!", "hannes"); 0, 0, 0, "de", "comment", "author");
// new MapFileInfo(new BoundingBox(-180, -90, 180, 90),
// new Byte((byte) 0), null, "Mercator",
// 0, 0, 0, "de", "yo!", "by me");
private boolean mOpenFile = false; private boolean mOpenFile = false;
private Connection connection = null; private Connection connection = null;
private static HashMap<Entry<String, String>, Tag> tagHash = new HashMap<Entry<String, String>, Tag>( private static volatile HashMap<Entry<String, String>, Tag> tagHash =
100); new HashMap<Entry<String, String>, Tag>(100);
private PreparedStatement prepQuery = null; private PreparedStatement prepQuery = null;
private boolean connect() { private boolean connect() {
@ -123,7 +120,6 @@ public class MapDatabase implements IMapDatabase {
byte[] b = null; byte[] b = null;
PGHStore h = null; PGHStore h = null;
// long id;
try { try {
while (r != null && r.next()) { while (r != null && r.next()) {
@ -131,9 +127,7 @@ public class MapDatabase implements IMapDatabase {
mCoordPos = 0; mCoordPos = 0;
try { try {
// id = r.getLong(1); Object obj = r.getObject(1);
Object obj = r.getObject(2);
h = null; h = null;
if (obj instanceof PGHStore) if (obj instanceof PGHStore)
@ -141,7 +135,7 @@ public class MapDatabase implements IMapDatabase {
else else
continue; continue;
b = r.getBytes(3); b = r.getBytes(2);
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
@ -184,6 +178,11 @@ public class MapDatabase implements IMapDatabase {
} }
} }
@Override
public String getMapProjection() {
return WebMercator.NAME;
}
@Override @Override
public MapFileInfo getMapFileInfo() { public MapFileInfo getMapFileInfo() {
return mMapInfo; return mMapInfo;