MapView base layer is now a TileLayer

- extract MapView base layer into TileLayer
- extract MapTile loading from GLRenderer
- move all tile layer related classes to layers.tile.*
- make Overlay subclass of InputLayer, which extends Layer
This commit is contained in:
Hannes Janetzek 2013-04-21 23:20:23 +02:00
parent 1c779f2f60
commit 6eb3b9221b
32 changed files with 1398 additions and 1340 deletions

View File

@ -15,7 +15,7 @@
*/ */
package org.oscim.database; package org.oscim.database;
import org.oscim.generator.JobTile; import org.oscim.layers.tile.JobTile;
/** /**
* *

View File

@ -27,7 +27,7 @@ import org.oscim.database.MapOptions;
import org.oscim.database.mapfile.header.MapFileHeader; import org.oscim.database.mapfile.header.MapFileHeader;
import org.oscim.database.mapfile.header.MapFileInfo; import org.oscim.database.mapfile.header.MapFileInfo;
import org.oscim.database.mapfile.header.SubFileParameter; import org.oscim.database.mapfile.header.SubFileParameter;
import org.oscim.generator.JobTile; import org.oscim.layers.tile.JobTile;
import android.util.Log; import android.util.Log;

View File

@ -30,7 +30,7 @@ import org.oscim.database.IMapDatabase;
import org.oscim.database.IMapDatabaseCallback; import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.MapInfo; import org.oscim.database.MapInfo;
import org.oscim.database.MapOptions; import org.oscim.database.MapOptions;
import org.oscim.generator.JobTile; import org.oscim.layers.tile.JobTile;
import android.os.Environment; import android.os.Environment;
import android.os.SystemClock; import android.os.SystemClock;

View File

@ -43,7 +43,7 @@ import org.oscim.database.IMapDatabase;
import org.oscim.database.IMapDatabaseCallback; import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.MapInfo; import org.oscim.database.MapInfo;
import org.oscim.database.MapOptions; import org.oscim.database.MapOptions;
import org.oscim.generator.JobTile; import org.oscim.layers.tile.JobTile;
import android.os.Environment; import android.os.Environment;
import android.os.SystemClock; import android.os.SystemClock;

View File

@ -26,7 +26,7 @@ import org.oscim.database.IMapDatabase;
import org.oscim.database.IMapDatabaseCallback; import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.MapInfo; import org.oscim.database.MapInfo;
import org.oscim.database.MapOptions; import org.oscim.database.MapOptions;
import org.oscim.generator.JobTile; import org.oscim.layers.tile.JobTile;
/** /**
* *

View File

@ -0,0 +1,228 @@
/*
* Copyright 2012 osmdroid authors
* Copyright 2013 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.oscim.layers;
import org.oscim.view.MapView;
import android.view.KeyEvent;
import android.view.MotionEvent;
public abstract class InputLayer extends Layer {
public InputLayer(MapView mapView) {
super(mapView);
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param keyCode
* ...
* @param event
* ...
* @return ...
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param keyCode
* ...
* @param event
* ...
* @return ...
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
return false;
}
/**
* <b>You can prevent all(!) other Touch-related events from happening!</b><br />
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onTouchEvent(MotionEvent e) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onTrackballEvent(MotionEvent e) {
return false;
}
/** GestureDetector.OnDoubleTapListener **/
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onDoubleTap(MotionEvent e) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onSingleTapConfirmed(MotionEvent e) {
return false;
}
/** OnGestureListener **/
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onDown(MotionEvent e) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param pEvent1
* ...
* @param pEvent2
* ...
* @param pVelocityX
* ...
* @param pVelocityY
* ...
* @return ...
*/
public boolean onFling(MotionEvent pEvent1, MotionEvent pEvent2,
float pVelocityX, float pVelocityY) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onLongPress(MotionEvent e) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param pEvent1
* ...
* @param pEvent2
* ...
* @param pDistanceX
* ...
* @param pDistanceY
* ...
* @return ...
*/
public boolean onScroll(MotionEvent pEvent1, MotionEvent pEvent2,
float pDistanceX, float pDistanceY) {
return false;
}
/**
* @param pEvent
* ...
*/
public void onShowPress(MotionEvent pEvent) {
return;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2013 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.oscim.layers;
import org.oscim.core.MapPosition;
import org.oscim.renderer.overlays.RenderOverlay;
import org.oscim.view.MapView;
public class Layer {
public Layer(MapView mapView) {
mMapView = mapView;
}
private boolean mEnabled = true;
protected final MapView mMapView;
/** RenderOverlay used to draw this layer. To be implemented by sub-classes */
protected RenderOverlay mLayer;
public RenderOverlay getLayer() {
return mLayer;
}
/**
*/
public void setEnabled(boolean pEnabled) {
mEnabled = pEnabled;
}
/**
*/
public boolean isEnabled() {
return mEnabled;
}
/**
* Called before each frame render request (on main thread).
*
* @param mapPosition
* current MapPosition
* @param changed
* true when MapPosition has changed since last call
*/
public void onUpdate(MapPosition mapPosition, boolean changed) {
}
/**
* Override to perform clean up of resources before shutdown. By default
* does nothing.
*/
public void onDetach() {
// FIXME call to this function is not implemented
}
public void destroy() {
// TODO Auto-generated method stub
}
}

View File

@ -13,10 +13,10 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.generator; package org.oscim.layers.tile;
import static org.oscim.generator.JobTile.STATE_LOADING; import static org.oscim.layers.tile.JobTile.STATE_LOADING;
import static org.oscim.generator.JobTile.STATE_NONE; import static org.oscim.layers.tile.JobTile.STATE_NONE;
/** /**
* A JobQueue keeps the list of pending jobs for a MapView and prioritizes them. * A JobQueue keeps the list of pending jobs for a MapView and prioritizes them.

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.generator; package org.oscim.layers.tile;
import org.oscim.core.Tile; import org.oscim.core.Tile;

View File

@ -12,11 +12,11 @@
* You should have received a copy of the GNU Lesser General License along with * You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.renderer; package org.oscim.layers.tile;
import org.oscim.generator.JobTile;
import org.oscim.renderer.layer.Layers; import org.oscim.renderer.layer.Layers;
import org.oscim.renderer.layer.TextItem; import org.oscim.renderer.layer.TextItem;
import org.oscim.utils.quadtree.QuadTree;
/** /**
* Extends Tile class for concurrent use in TileManager, * Extends Tile class for concurrent use in TileManager,
@ -41,7 +41,7 @@ public final class MapTile extends JobTile {
/** /**
* Pointer to access relatives in QuadTree * Pointer to access relatives in QuadTree
*/ */
public QuadTree rel; public QuadTree<MapTile> rel;
int lastDraw = 0; int lastDraw = 0;
@ -92,42 +92,40 @@ public final class MapTile extends JobTile {
return; return;
// lock all tiles that could serve as proxy // lock all tiles that could serve as proxy
MapTile p = rel.parent.tile; MapTile p = rel.parent.item;
if (p != null && (p.state != 0)) { if (p != null && (p.state != 0)) {
proxies |= PROXY_PARENT; proxies |= PROXY_PARENT;
p.refs++; p.refs++;
} }
p = rel.parent.parent.tile; p = rel.parent.parent.item;
if (p != null && (p.state != 0)) { if (p != null && (p.state != 0)) {
proxies |= PROXY_GRAMPA; proxies |= PROXY_GRAMPA;
p.refs++; p.refs++;
} }
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
if (rel.child[j] != null) { if ((p = rel.get(j)) == null || p.state == 0)
p = rel.child[j].tile; continue;
if (p != null && (p.state != 0)) {
proxies |= (1 << j); proxies |= (1 << j);
p.refs++; p.refs++;
} }
} }
}
}
void unlock() { void unlock() {
if (--locked > 0 || proxies == 0) if (--locked > 0 || proxies == 0)
return; return;
if ((proxies & PROXY_PARENT) != 0) if ((proxies & PROXY_PARENT) != 0)
rel.parent.tile.refs--; rel.parent.item.refs--;
if ((proxies & PROXY_GRAMPA) != 0) if ((proxies & PROXY_GRAMPA) != 0)
rel.parent.parent.tile.refs--; rel.parent.parent.item.refs--;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if ((proxies & (1 << i)) != 0) if ((proxies & (1 << i)) != 0)
rel.child[i].tile.refs--; rel.get(i).refs--;
} }
proxies = 0; proxies = 0;
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2010, 2011, 2012 mapsforge.org
* * Copyright 2013 Hannes Hannes Janetzek
* This program is free software: you can redistribute it and/or modify it under the * 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 * 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. * Foundation, either version 3 of the License, or (at your option) any later version.
@ -12,9 +12,8 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.generator; package org.oscim.layers.tile;
import org.oscim.renderer.TileManager;
import org.oscim.utils.PausableThread; import org.oscim.utils.PausableThread;
/** /**
@ -39,6 +38,7 @@ public class MapWorker extends PausableThread {
*/ */
public MapWorker(int id, JobQueue jobQueue, TileGenerator tileGenerator, public MapWorker(int id, JobQueue jobQueue, TileGenerator tileGenerator,
TileManager tileManager) { TileManager tileManager) {
super(); super();
mJobQueue = jobQueue; mJobQueue = jobQueue;
mMapGenerator = tileGenerator; mMapGenerator = tileGenerator;

View File

@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.generator; package org.oscim.layers.tile;
/** /**
* Sort Tiles by 'distance' value. * Sort Tiles by 'distance' value.

View File

@ -12,11 +12,12 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.generator; package org.oscim.layers.tile;
import static org.oscim.core.MapElement.GEOM_LINE; import static org.oscim.core.MapElement.GEOM_LINE;
import static org.oscim.core.MapElement.GEOM_POINT; import static org.oscim.core.MapElement.GEOM_POINT;
import static org.oscim.core.MapElement.GEOM_POLY; import static org.oscim.core.MapElement.GEOM_POLY;
import static org.oscim.generator.JobTile.STATE_NONE; import static org.oscim.layers.tile.JobTile.STATE_NONE;
import java.util.Arrays; import java.util.Arrays;
@ -25,9 +26,8 @@ import org.oscim.core.MercatorProjection;
import org.oscim.core.Tag; import org.oscim.core.Tag;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.database.IMapDatabase; import org.oscim.database.IMapDatabase;
import org.oscim.database.IMapDatabase.QueryResult;
import org.oscim.database.IMapDatabaseCallback; import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.QueryResult;
import org.oscim.renderer.MapTile;
import org.oscim.renderer.layer.ExtrusionLayer; import org.oscim.renderer.layer.ExtrusionLayer;
import org.oscim.renderer.layer.Layers; import org.oscim.renderer.layer.Layers;
import org.oscim.renderer.layer.LineLayer; import org.oscim.renderer.layer.LineLayer;
@ -71,12 +71,18 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
private static final Tag[] debugTagWay = { new Tag("debug", "way") }; private static final Tag[] debugTagWay = { new Tag("debug", "way") };
private static final Tag[] debugTagArea = { new Tag("debug", "area") }; private static final Tag[] debugTagArea = { new Tag("debug", "area") };
// replacement for variable value tags that should not be matched by RenderTheme
// FIXME make this general, maybe subclass tags
private static final Tag mTagEmptyName = new Tag(Tag.TAG_KEY_NAME, null, false);
private static final Tag mTagEmptyHouseNr = new Tag(Tag.TAG_KEY_HOUSE_NUMBER, null, false);
private final MapElement mDebugWay, mDebugPoint; private final MapElement mDebugWay, mDebugPoint;
private static RenderTheme renderTheme;
private static int renderLevels;
private static DebugSettings debug; private static DebugSettings debug;
private RenderTheme renderTheme;
private int renderLevels;
// current MapDatabase used by this TileGenerator // current MapDatabase used by this TileGenerator
private IMapDatabase mMapDatabase; private IMapDatabase mMapDatabase;
@ -95,16 +101,12 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
private float mLatScaleFactor; private float mLatScaleFactor;
private float mGroundResolution; private float mGroundResolution;
// replacement for variable value tags that should not be matched by RenderTheme
// FIXME make this general, maybe subclass tags
private final static Tag mTagEmptyName = new Tag(Tag.TAG_KEY_NAME, null, false);
private final static Tag mTagEmptyHouseNr = new Tag(Tag.TAG_KEY_HOUSE_NUMBER, null, false);
private Tag mTagName; private Tag mTagName;
private Tag mTagHouseNr; private Tag mTagHouseNr;
private final LineClipper mClipper; private final LineClipper mClipper;
public static void setRenderTheme(RenderTheme theme) { public void setRenderTheme(RenderTheme theme) {
renderTheme = theme; renderTheme = theme;
renderLevels = theme.getLevels(); renderLevels = theme.getLevels();
} }
@ -129,7 +131,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
m.tags = new Tag[] { new Tag("debug", "box") }; m.tags = new Tag[] { new Tag("debug", "box") };
m.geometryType = GEOM_LINE; m.geometryType = GEOM_LINE;
m = mDebugPoint= new MapElement(); m = mDebugPoint = new MapElement();
m.startPoints(); m.startPoints();
m.addPoint(s >> 1, 10); m.addPoint(s >> 1, 10);
m.geometryType = GEOM_POINT; m.geometryType = GEOM_POINT;
@ -309,7 +311,6 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
mElement = null; mElement = null;
} }
private void debugUnmatched(boolean closed, Tag[] tags) { private void debugUnmatched(boolean closed, Tag[] tags) {
Log.d(TAG, "DBG way not matched: " + closed + " " Log.d(TAG, "DBG way not matched: " + closed + " "
+ Arrays.deepToString(tags)); + Arrays.deepToString(tags));

View File

@ -0,0 +1,332 @@
/*
* Copyright 2013 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.oscim.layers.tile;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
import org.oscim.database.IMapDatabase;
import org.oscim.database.IMapDatabase.OpenResult;
import org.oscim.database.MapDatabaseFactory;
import org.oscim.database.MapDatabases;
import org.oscim.database.MapInfo;
import org.oscim.database.MapOptions;
import org.oscim.layers.Layer;
import org.oscim.renderer.GLRenderer;
import org.oscim.theme.ExternalRenderTheme;
import org.oscim.theme.InternalRenderTheme;
import org.oscim.theme.RenderTheme;
import org.oscim.theme.RenderThemeHandler;
import org.oscim.theme.Theme;
import org.oscim.view.MapView;
import org.xml.sax.SAXException;
import android.util.Log;
public class TileLayer extends Layer {
private final static String TAG = TileLayer.class.getName();
private boolean mClearMap = true;
private final TileManager mTileManager;
private final JobQueue mJobQueue;
// TODO use 1 download and 1 generator thread instead
private final MapWorker mMapWorkers[];
private final int mNumMapWorkers = 4;
private final TileGenerator mTileGenerators[];
public TileLayer(MapView mapView) {
super(mapView);
mTileManager = new TileManager(mapView, this);
mJobQueue = new JobQueue();
mMapWorkers = new MapWorker[mNumMapWorkers];
mTileGenerators = new TileGenerator[mNumMapWorkers];
TileGenerator.setDebugSettings(mapView.getDebugSettings());
for (int i = 0; i < mNumMapWorkers; i++) {
mTileGenerators[i] = new TileGenerator();
mMapWorkers[i] = new MapWorker(i, mJobQueue, mTileGenerators[i], mTileManager);
mMapWorkers[i].start();
}
mLayer = new TileRenderLayer(mapView, mTileManager);
}
public TileRenderLayer getTileLayer(){
return (TileRenderLayer)mLayer;
}
@Override
public void onUpdate(MapPosition mapPosition, boolean changed) {
if (mClearMap){
mTileManager.init(mMapView.getWidth(), mMapView.getHeight());
mClearMap = false;
changed = true;
Log.d(TAG, "init TileManager ----- ");
}
if (changed)
mTileManager.update(mapPosition);
}
@Override
public void destroy(){
mTileManager.destroy();
for (MapWorker mapWorker : mMapWorkers) {
mapWorker.pause();
mapWorker.interrupt();
mapWorker.getTileGenerator().getMapDatabase().close();
try {
mapWorker.join(10000);
} catch (InterruptedException e) {
// restore the interrupted status
Thread.currentThread().interrupt();
}
}
}
private void clearMap() {
// clear tile and overlay data before next draw
mClearMap = true;
}
private MapOptions mMapOptions;
private IMapDatabase mMapDatabase;
private String mRenderTheme;
/**
* Sets the MapDatabase for this MapView.
*
* @param options
* the new MapDatabase options.
* @return true if MapDatabase changed
*/
public boolean setMapDatabase(MapOptions options) {
Log.i(TAG, "setMapDatabase: " + options.db.name());
if (mMapOptions != null && mMapOptions.equals(options))
return true;
mapWorkersPause(true);
mJobQueue.clear();
mMapOptions = options;
mMapDatabase = null;
for (int i = 0; i < mNumMapWorkers; i++) {
MapWorker mapWorker = mMapWorkers[i];
IMapDatabase mapDatabase = MapDatabaseFactory
.createMapDatabase(options.db);
OpenResult result = mapDatabase.open(options);
if (result != OpenResult.SUCCESS) {
Log.d(TAG, "failed open db: " + result.getErrorMessage());
}
TileGenerator tileGenerator = mapWorker.getTileGenerator();
tileGenerator.setMapDatabase(mapDatabase);
// TODO this could be done in a cleaner way..
if (mMapDatabase == null)
mMapDatabase = mapDatabase;
}
if (options.db == MapDatabases.OSCIMAP_READER ||
options.db == MapDatabases.MAP_READER ||
options.db == MapDatabases.TEST_READER)
MapView.enableClosePolygons = true;
else
MapView.enableClosePolygons = false;
clearMap();
mapWorkersProceed();
return true;
}
public Map<String, String> getMapOptions() {
return mMapOptions;
}
public MapPosition getMapFileCenter() {
if (mMapDatabase == null)
return null;
MapInfo mapInfo = mMapDatabase.getMapInfo();
if (mapInfo == null)
return null;
GeoPoint startPos = mapInfo.startPosition;
if (startPos == null)
startPos = mapInfo.mapCenter;
if (startPos == null)
startPos = new GeoPoint(0, 0);
MapPosition mapPosition = new MapPosition();
mapPosition.setPosition(startPos);
if (mapInfo.startZoomLevel == null)
mapPosition.setZoomLevel(12);
else
mapPosition.setZoomLevel((mapInfo.startZoomLevel).byteValue());
return mapPosition;
}
public String getRenderTheme() {
return mRenderTheme;
}
/**
* Sets the internal theme which is used for rendering the map.
*
* @param internalRenderTheme
* the internal rendering theme.
* @return ...
* @throws IllegalArgumentException
* if the supplied internalRenderTheme is null.
*/
public boolean setRenderTheme(InternalRenderTheme internalRenderTheme) {
if (internalRenderTheme == null) {
throw new IllegalArgumentException("render theme must not be null");
}
if (internalRenderTheme.name() == mRenderTheme)
return true;
boolean ret = setRenderTheme((Theme) internalRenderTheme);
if (ret) {
mRenderTheme = internalRenderTheme.name();
}
clearMap();
return ret;
}
/**
* Sets the theme file which is used for rendering the map.
*
* @param renderThemePath
* the path to the XML file which defines the rendering theme.
* @throws IllegalArgumentException
* if the supplied internalRenderTheme is null.
* @throws FileNotFoundException
* if the supplied file does not exist, is a directory or cannot
* be read.
*/
public void setRenderTheme(String renderThemePath) throws FileNotFoundException {
if (renderThemePath == null) {
throw new IllegalArgumentException("render theme path must not be null");
}
boolean ret = setRenderTheme(new ExternalRenderTheme(renderThemePath));
if (ret) {
mRenderTheme = renderThemePath;
}
clearMap();
}
private boolean setRenderTheme(Theme theme) {
mapWorkersPause(true);
InputStream inputStream = null;
try {
inputStream = theme.getRenderThemeAsStream();
RenderTheme t = RenderThemeHandler.getRenderTheme(inputStream);
t.scaleTextSize(1 + (MapView.dpi / 240 - 1) * 0.5f);
// FIXME !!!
GLRenderer.setRenderTheme(t);
for (TileGenerator g : mTileGenerators)
g.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 {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
mapWorkersProceed();
}
return false;
}
/**
* add jobs and remember MapWorkers that stuff needs to be done
*
* @param jobs
* tile jobs
*/
public void addJobs(JobTile[] jobs) {
if (jobs == null) {
mJobQueue.clear();
return;
}
mJobQueue.setJobs(jobs);
for (int i = 0; i < mNumMapWorkers; i++) {
MapWorker m = mMapWorkers[i];
synchronized (m) {
m.notify();
}
}
}
private void mapWorkersPause(boolean wait) {
for (MapWorker mapWorker : mMapWorkers) {
if (!mapWorker.isPausing())
mapWorker.pause();
}
if (wait) {
for (MapWorker mapWorker : mMapWorkers) {
if (!mapWorker.isPausing())
mapWorker.awaitPausing();
}
}
}
private void mapWorkersProceed() {
for (MapWorker mapWorker : mMapWorkers)
mapWorker.proceed();
}
}

View File

@ -13,21 +13,24 @@
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.renderer; package org.oscim.layers.tile;
import static org.oscim.generator.JobTile.STATE_LOADING; import static org.oscim.layers.tile.JobTile.STATE_LOADING;
import static org.oscim.generator.JobTile.STATE_NEW_DATA; import static org.oscim.layers.tile.JobTile.STATE_NEW_DATA;
import static org.oscim.generator.JobTile.STATE_NONE; import static org.oscim.layers.tile.JobTile.STATE_NONE;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.generator.JobTile; import org.oscim.renderer.BufferObject;
import org.oscim.generator.TileDistanceSort; import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.ScanBox;
import org.oscim.renderer.layer.TextItem; import org.oscim.renderer.layer.TextItem;
import org.oscim.utils.FastMath; import org.oscim.utils.FastMath;
import org.oscim.utils.quadtree.QuadTree;
import org.oscim.utils.quadtree.QuadTreeIndex;
import org.oscim.view.MapView; import org.oscim.view.MapView;
import org.oscim.view.MapViewPosition; import org.oscim.view.MapViewPosition;
@ -40,6 +43,8 @@ import android.util.Log;
* - make it general for reuse in tile-overlays * - make it general for reuse in tile-overlays
*/ */
public class TileManager { public class TileManager {
private static final int CACHE_TILES_MAX = 250;
static final String TAG = TileManager.class.getSimpleName(); static final String TAG = TileManager.class.getSimpleName();
private final static int MAX_ZOOMLEVEL = 17; private final static int MAX_ZOOMLEVEL = 17;
private final static int MIN_ZOOMLEVEL = 2; private final static int MIN_ZOOMLEVEL = 2;
@ -71,21 +76,53 @@ public class TileManager {
private final ArrayList<JobTile> mJobs; private final ArrayList<JobTile> mJobs;
// counter to check whether current TileSet has changed // counter to check whether current TileSet has changed
private static int mUpdateSerial; private int mUpdateSerial;
// lock for TileSets while updating MapTile locks // lock for TileSets while updating MapTile locks
private final Object mTilelock = new Object(); private final Object mTilelock = new Object();
// need to keep track of TileSets to clear on reset...
private final ArrayList<TileSet> mTileSets = new ArrayList<TileSet>(4);
private TileSet mCurrentTiles; private TileSet mCurrentTiles;
/* package */TileSet mNewTiles; /* package */TileSet mNewTiles;
private final float[] mBoxCoords = new float[8];
public TileManager(MapView mapView) { private final QuadTreeIndex<MapTile> mIndex = new QuadTreeIndex<MapTile>(){
@Override
public MapTile create(int x, int y, int z) {
QuadTree<MapTile> t = super.add(x, y, z);
t.item = new MapTile(x, y, (byte)z);
t.item.rel = t;
return t.item;
}
@Override
public void remove(MapTile t) {
if (t.rel == null) {
Log.d(TAG, "BUG already removed " + t);
return;
}
super.remove(t.rel);
t.rel.item = null;
t.rel = null;
}
};
private final float[] mBoxCoords = new float[8];
private final TileLayer mTileLayer;
public TileManager(MapView mapView, TileLayer tileLayer) {
mMapView = mapView; mMapView = mapView;
mTileLayer = tileLayer;
mMapViewPosition = mapView.getMapViewPosition(); mMapViewPosition = mapView.getMapViewPosition();
mJobs = new ArrayList<JobTile>(); mJobs = new ArrayList<JobTile>();
mTiles = new MapTile[GLRenderer.CACHE_TILES]; mTiles = new MapTile[CACHE_TILES_MAX];
mTilesSize = 0; mTilesSize = 0;
mTilesForUpload = 0; mTilesForUpload = 0;
@ -119,7 +156,7 @@ public class TileManager {
//} //}
// clear cache index // clear cache index
QuadTree.init(); //QuadTree.init();
// clear references to cached MapTiles // clear references to cached MapTiles
Arrays.fill(mTiles, null); Arrays.fill(mTiles, null);
@ -160,7 +197,7 @@ public class TileManager {
// start with old jobs while new jobs are calculated, which // start with old jobs while new jobs are calculated, which
// should increase the chance that they are free when new // should increase the chance that they are free when new
// jobs come in. // jobs come in.
mMapView.addJobs(null); mTileLayer.addJobs(null);
// load some tiles more than currently visible (* 0.75) // load some tiles more than currently visible (* 0.75)
double scale = pos.scale * 0.9f; double scale = pos.scale * 0.9f;
@ -223,11 +260,11 @@ public class TileManager {
updateTileDistances(jobs, jobs.length, pos); updateTileDistances(jobs, jobs.length, pos);
// sets tiles to state == LOADING // sets tiles to state == LOADING
mMapView.addJobs(jobs); mTileLayer.addJobs(jobs);
mJobs.clear(); mJobs.clear();
/* limit cache items */ /* limit cache items */
int remove = mTilesCount - GLRenderer.CACHE_TILES; int remove = mTilesCount - CACHE_TILES_MAX;
if (remove > CACHE_THRESHOLD || if (remove > CACHE_THRESHOLD ||
mTilesForUpload > MAX_TILES_IN_QUEUE) mTilesForUpload > MAX_TILES_IN_QUEUE)
@ -235,9 +272,13 @@ public class TileManager {
limitCache(pos, remove); limitCache(pos, remove);
} }
// need to keep track of TileSets to clear on reset...
private static ArrayList<TileSet> mTileSets = new ArrayList<TileSet>(2);
/**
* Retrive a TileSet of current tiles.
* Tiles remain locked in cache until the set is unlocked by either passing
* it again to this function or to releaseTiles. If passed TileSet is null
* it will be allocated.
*/
public TileSet getActiveTiles(TileSet td) { public TileSet getActiveTiles(TileSet td) {
if (mCurrentTiles == null) if (mCurrentTiles == null)
return td; return td;
@ -287,11 +328,11 @@ public class TileManager {
/* package */MapTile addTile(int x, int y, int zoomLevel) { /* package */MapTile addTile(int x, int y, int zoomLevel) {
MapTile tile; MapTile tile;
tile = QuadTree.getTile(x, y, zoomLevel); //tile = QuadTree.getTile(x, y, zoomLevel);
tile = mIndex.getTile(x, y, zoomLevel);
if (tile == null) { if (tile == null) {
tile = new MapTile(x, y, (byte) zoomLevel); tile = mIndex.create(x, y, zoomLevel);
QuadTree.add(tile);
mJobs.add(tile); mJobs.add(tile);
addToCache(tile); addToCache(tile);
} else if (!tile.isActive()) { } else if (!tile.isActive()) {
@ -302,11 +343,11 @@ public class TileManager {
boolean add = false; boolean add = false;
// prefetch parent // prefetch parent
MapTile p = tile.rel.parent.tile; MapTile p = tile.rel.parent.item;
if (p == null) { if (p == null) {
p = new MapTile(x >> 1, y >> 1, (byte) (zoomLevel - 1)); p = mIndex.create(x >> 1, y >> 1, zoomLevel - 1);
QuadTree.add(p);
addToCache(p); addToCache(p);
add = true; add = true;
} }
@ -319,11 +360,10 @@ public class TileManager {
if (zoomLevel > 3) { if (zoomLevel > 3) {
// prefetch grand parent // prefetch grand parent
p = tile.rel.parent.parent.tile; p = tile.rel.parent.parent.item;
add = false; add = false;
if (p == null) { if (p == null) {
p = new MapTile(x >> 2, y >> 2, (byte) (zoomLevel - 2)); p = mIndex.create(x >> 2, y >> 2, zoomLevel - 2);
QuadTree.add(p);
addToCache(p); addToCache(p);
add = true; add = true;
} }
@ -376,7 +416,9 @@ public class TileManager {
TextItem.pool.releaseAll(t.labels); TextItem.pool.releaseAll(t.labels);
QuadTree.remove(t); mIndex.remove(t);
//QuadTree.remove(t);
t.state = STATE_NONE; t.state = STATE_NONE;
mTilesCount--; mTilesCount--;
@ -555,7 +597,7 @@ public class TileManager {
private final ScanBox mScanBox = new ScanBox() { private final ScanBox mScanBox = new ScanBox() {
@Override @Override
public void setVisible(int y, int x1, int x2) { protected void setVisible(int y, int x1, int x2) {
MapTile[] tiles = mNewTiles.tiles; MapTile[] tiles = mNewTiles.tiles;
int cnt = mNewTiles.cnt; int cnt = mNewTiles.cnt;
int maxTiles = tiles.length; int maxTiles = tiles.length;

View File

@ -0,0 +1,310 @@
/*
* Copyright 2013 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.oscim.layers.tile;
import static org.oscim.layers.tile.JobTile.STATE_NEW_DATA;
import static org.oscim.layers.tile.JobTile.STATE_READY;
import org.oscim.core.MapPosition;
import org.oscim.renderer.BufferObject;
import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.GLRenderer.Matrices;
import org.oscim.renderer.ScanBox;
import org.oscim.renderer.overlays.RenderOverlay;
import org.oscim.view.MapView;
import android.util.Log;
public class TileRenderLayer extends RenderOverlay {
private final static String TAG = TileRenderLayer.class.getName();
private final float[] mBoxCoords;
private final TileManager mTileManager;
public TileRenderLayer(MapView mapView, TileManager tileManager) {
super(mapView);
mTileManager = tileManager;
mBoxCoords = new float[8];
}
@Override
public void update(MapPosition curPos, boolean positionChanged, boolean tilesChanged,
Matrices matrices) {
int serial = 0;
mMapPosition.copy(curPos);
if (mDrawTiles != null)
serial = mDrawTiles.getSerial();
synchronized (tilelock) {
// get current tiles to draw
mDrawTiles = mTileManager.getActiveTiles(mDrawTiles);
}
if (mDrawTiles == null || mDrawTiles.cnt == 0)
return;
if (positionChanged)
mMapView.getMapViewPosition().getMapViewProjection(mBoxCoords);
boolean changed = false;
//boolean positionChanged = false;
// check if the tiles have changed...
if (serial != mDrawTiles.getSerial()) {
changed = true;
// FIXME needed?
//positionChanged = true;
}
int tileCnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles;
if (changed || positionChanged)
updateTileVisibility();
tileCnt += mNumTileHolder;
/* prepare tile for rendering */
int uploadCnt = compileTileLayers(tiles, tileCnt);
tilesChanged |= (uploadCnt > 0);
TileRenderer.draw(tiles, tileCnt, curPos, matrices);
}
@Override
public void compile() {
}
@Override
public void render(MapPosition pos, Matrices m) {
}
/** compile tile layer data and upload to VBOs */
private static int compileTileLayers(MapTile[] tiles, int tileCnt) {
int uploadCnt = 0;
for (int i = 0; i < tileCnt; i++) {
MapTile tile = tiles[i];
if (!tile.isVisible)
continue;
if (tile.state == STATE_READY)
continue;
if (tile.state == STATE_NEW_DATA) {
uploadTileData(tile);
continue;
}
if (tile.holder != null) {
// load tile that is referenced by this holder
if (tile.holder.state == STATE_NEW_DATA)
uploadTileData(tile.holder);
tile.state = tile.holder.state;
continue;
}
// check near relatives than can serve as proxy
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
MapTile rel = tile.rel.parent.item;
if (rel.state == STATE_NEW_DATA)
uploadTileData(rel);
// dont load child proxies
continue;
}
for (int c = 0; c < 4; c++) {
if ((tile.proxies & 1 << c) == 0)
continue;
MapTile rel = tile.rel.get(i);
if (rel != null && rel.state == STATE_NEW_DATA)
uploadTileData(rel);
}
}
if (uploadCnt > 0)
GLRenderer.checkBufferUsage(false);
return uploadCnt;
}
private static void uploadTileData(MapTile tile) {
tile.state = STATE_READY;
if (tile.layers == null)
return;
int newSize = tile.layers.getSize();
if (newSize > 0) {
if (tile.layers.vbo == null)
tile.layers.vbo = BufferObject.get(newSize);
if (!GLRenderer.uploadLayers(tile.layers, newSize, true)) {
Log.d(TAG, "BUG uploadTileData " + tile + " failed!");
BufferObject.release(tile.layers.vbo);
tile.layers.vbo = null;
tile.layers.clear();
tile.layers = null;
}
}
}
private final Object tilelock = new Object();
/** set tile isVisible flag true for tiles that intersect view */
private void updateTileVisibility() {
// lock tiles while updating isVisible state
synchronized (tilelock) {
MapPosition pos = mMapPosition;
MapTile[] tiles = mDrawTiles.tiles;
int tileZoom = tiles[0].zoomLevel;
for (int i = 0; i < mDrawTiles.cnt; i++)
tiles[i].isVisible = false;
// count placeholder tiles
mNumTileHolder = 0;
// check visibile tiles
mScanBox.scan(pos.x, pos.y, pos.scale, tileZoom, mBoxCoords);
}
}
// get a TileSet of currently visible tiles
public TileSet getVisibleTiles(TileSet td) {
if (mDrawTiles == null)
return td;
// ensure tiles keep visible state
synchronized (tilelock) {
MapTile[] newTiles = mDrawTiles.tiles;
int cnt = mDrawTiles.cnt;
if (td == null)
td = new TileSet(newTiles.length);
// unlock previous tiles
for (int i = 0; i < td.cnt; i++)
td.tiles[i].unlock();
// lock tiles to not be removed from cache
td.cnt = 0;
for (int i = 0; i < cnt; i++) {
MapTile t = newTiles[i];
if (t.isVisible && t.state == STATE_READY) {
t.lock();
td.tiles[td.cnt++] = t;
}
}
}
return td;
}
public void releaseTiles(TileSet td) {
for (int i = 0; i < td.cnt; i++) {
td.tiles[i].unlock();
td.tiles[i] = null;
}
td.cnt = 0;
}
// Add additional tiles that serve as placeholer when flipping
// over date-line.
// I dont really like this but cannot think of a better solution:
// the other option would be to run scanbox each time for upload,
// drawing, proxies and text layer. needing to add placeholder only
// happens rarely, unless you live on Fidschi
/* package */int mNumTileHolder;
/* package */TileSet mDrawTiles;
// scanline fill class used to check tile visibility
private final ScanBox mScanBox = new ScanBox() {
@Override
protected void setVisible(int y, int x1, int x2) {
int cnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles;
for (int i = 0; i < cnt; i++) {
MapTile t = tiles[i];
if (t.tileY == y && t.tileX >= x1 && t.tileX < x2)
t.isVisible = true;
}
int xmax = 1 << mZoom;
if (x1 >= 0 && x2 < xmax)
return;
// add placeholder tiles to show both sides
// of date line. a little too complicated...
for (int x = x1; x < x2; x++) {
MapTile holder = null;
MapTile tile = null;
boolean found = false;
if (x >= 0 && x < xmax)
continue;
int xx = x;
if (x < 0)
xx = xmax + x;
else
xx = x - xmax;
if (xx < 0 || xx >= xmax)
continue;
for (int i = cnt; i < cnt + mNumTileHolder; i++)
if (tiles[i].tileX == x && tiles[i].tileY == y) {
found = true;
break;
}
if (found)
continue;
for (int i = 0; i < cnt; i++)
if (tiles[i].tileX == xx && tiles[i].tileY == y) {
tile = tiles[i];
break;
}
if (tile == null)
continue;
holder = new MapTile(x, y, (byte) mZoom);
holder.isVisible = true;
holder.holder = tile;
tile.isVisible = true;
tiles[cnt + mNumTileHolder++] = holder;
}
}
};
}

View File

@ -12,18 +12,23 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.renderer; package org.oscim.layers.tile;
import static android.opengl.GLES20.GL_ARRAY_BUFFER; import static android.opengl.GLES20.GL_ARRAY_BUFFER;
import static android.opengl.GLES20.glStencilMask; import static android.opengl.GLES20.glStencilMask;
import static org.oscim.generator.JobTile.STATE_READY; import static org.oscim.layers.tile.JobTile.STATE_READY;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.GLRenderer.Matrices; import org.oscim.renderer.GLRenderer.Matrices;
import org.oscim.renderer.LineRenderer;
import org.oscim.renderer.LineTexRenderer;
import org.oscim.renderer.PolygonRenderer;
import org.oscim.renderer.layer.Layer; import org.oscim.renderer.layer.Layer;
import org.oscim.utils.FastMath; import org.oscim.utils.FastMath;
import org.oscim.utils.Matrix4; import org.oscim.utils.Matrix4;
import org.oscim.utils.quadtree.QuadTree;
import android.opengl.GLES20; import android.opengl.GLES20;
@ -56,6 +61,8 @@ public class TileRenderer {
// discard z projection from tilt // discard z projection from tilt
mProjMatrix.setValue(10, 0); mProjMatrix.setValue(10, 0);
mProjMatrix.setValue(14, 0); mProjMatrix.setValue(14, 0);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT);
//GLES20.GL_STENCIL_BUFFER_BIT);
GLES20.glDepthFunc(GLES20.GL_LESS); GLES20.glDepthFunc(GLES20.GL_LESS);
@ -188,7 +195,7 @@ public class TileRenderer {
if ((tile.proxies & 1 << i) == 0) if ((tile.proxies & 1 << i) == 0)
continue; continue;
MapTile c = tile.rel.child[i].tile; MapTile c = tile.rel.get(i);
if (c.state == STATE_READY) { if (c.state == STATE_READY) {
drawTile(c, pos); drawTile(c, pos);
@ -200,10 +207,9 @@ public class TileRenderer {
// just FIXME! // just FIXME!
private static void drawProxyTile(MapTile tile, MapPosition pos, boolean parent, boolean preferParent) { private static void drawProxyTile(MapTile tile, MapPosition pos, boolean parent, boolean preferParent) {
//int diff = pos.zoomLevel - tile.zoomLevel;
QuadTree r = tile.rel;
MapTile proxy;
QuadTree<MapTile> r = tile.rel;
MapTile proxy;
if (!preferParent) { if (!preferParent) {
// prefer drawing children // prefer drawing children
@ -213,7 +219,7 @@ public class TileRenderer {
if (parent) { if (parent) {
// draw parent proxy // draw parent proxy
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
proxy = r.parent.tile; proxy = r.parent.item;
if (proxy.state == STATE_READY) { if (proxy.state == STATE_READY) {
//Log.d(TAG, "1. draw parent " + proxy); //Log.d(TAG, "1. draw parent " + proxy);
drawTile(proxy, pos); drawTile(proxy, pos);
@ -222,12 +228,12 @@ public class TileRenderer {
} else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) { } else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
// check if parent was already drawn // check if parent was already drawn
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
proxy = r.parent.tile; proxy = r.parent.item;
if (proxy.state == STATE_READY) if (proxy.state == STATE_READY)
return; return;
} }
proxy = r.parent.parent.tile; proxy = r.parent.parent.item;
if (proxy.state == STATE_READY) if (proxy.state == STATE_READY)
drawTile(proxy, pos); drawTile(proxy, pos);
} }
@ -235,7 +241,7 @@ public class TileRenderer {
// prefer drawing parent // prefer drawing parent
if (parent) { if (parent) {
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
proxy = r.parent.tile; proxy = r.parent.item;
if (proxy != null && proxy.state == STATE_READY) { if (proxy != null && proxy.state == STATE_READY) {
//Log.d(TAG, "2. draw parent " + proxy); //Log.d(TAG, "2. draw parent " + proxy);
drawTile(proxy, pos); drawTile(proxy, pos);
@ -248,7 +254,7 @@ public class TileRenderer {
} else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) { } else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
// check if parent was already drawn // check if parent was already drawn
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
proxy = r.parent.tile; proxy = r.parent.item;
if (proxy.state == STATE_READY) if (proxy.state == STATE_READY)
return; return;
} }
@ -256,7 +262,7 @@ public class TileRenderer {
if (drawProxyChild(tile, pos) > 0) if (drawProxyChild(tile, pos) > 0)
return; return;
proxy = r.parent.parent.tile; proxy = r.parent.parent.item;
if (proxy.state == STATE_READY) if (proxy.state == STATE_READY)
drawTile(proxy, pos); drawTile(proxy, pos);
} }

View File

@ -12,10 +12,11 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.renderer; package org.oscim.layers.tile;
import java.util.Comparator; import java.util.Comparator;
/** /**
* use with TileManager.getActiveTiles(TileSet) to get the current tiles. tiles * use with TileManager.getActiveTiles(TileSet) to get the current tiles. tiles
* are locked to not be modifed until getActiveTiles passes them back on a * are locked to not be modifed until getActiveTiles passes them back on a
@ -27,10 +28,14 @@ public final class TileSet {
int serial; int serial;
public int getSerial(){
return serial;
}
TileSet() { TileSet() {
} }
TileSet(int numTiles) { public TileSet(int numTiles) {
tiles = new MapTile[numTiles]; tiles = new MapTile[numTiles];
} }

View File

@ -13,10 +13,9 @@
* You should have received a copy of the GNU Lesser General Public License along with * 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/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.oscim.generator; package org.oscim.layers.tile;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.renderer.MapTile;
import org.oscim.renderer.layer.TextItem; import org.oscim.renderer.layer.TextItem;
import org.oscim.theme.renderinstruction.Text; import org.oscim.theme.renderinstruction.Text;
import org.oscim.utils.GeometryUtils; import org.oscim.utils.GeometryUtils;

View File

@ -30,9 +30,9 @@ public class BuildingOverlay extends Overlay {
final ExtrusionOverlay mExtLayer; final ExtrusionOverlay mExtLayer;
public BuildingOverlay(MapView mapView) { public BuildingOverlay(MapView mapView, org.oscim.layers.tile.TileRenderLayer tileRenderLayer) {
super(mapView); super(mapView);
mExtLayer = new ExtrusionOverlay(mapView); mExtLayer = new ExtrusionOverlay(mapView, tileRenderLayer);
mLayer = mExtLayer; mLayer = mExtLayer;
} }

View File

@ -14,6 +14,7 @@
*/ */
package org.oscim.overlay; package org.oscim.overlay;
import org.oscim.layers.tile.TileRenderLayer;
import org.oscim.renderer.overlays.TextOverlay; import org.oscim.renderer.overlays.TextOverlay;
import org.oscim.view.MapView; import org.oscim.view.MapView;
@ -27,9 +28,9 @@ public class LabelingOverlay extends Overlay {
private final static String TAG = LabelingOverlay.class.getName(); private final static String TAG = LabelingOverlay.class.getName();
final TextOverlay mTextLayer; final TextOverlay mTextLayer;
public LabelingOverlay(MapView mapView) { public LabelingOverlay(MapView mapView, TileRenderLayer tileRenderLayer) {
super(mapView); super(mapView);
mTextLayer = new TextOverlay(mapView); mTextLayer = new TextOverlay(mapView, tileRenderLayer);
mLayer = mTextLayer; mLayer = mTextLayer;
} }

View File

@ -16,14 +16,10 @@
package org.oscim.overlay; package org.oscim.overlay;
import org.oscim.core.MapPosition;
import org.oscim.core.PointF; import org.oscim.core.PointF;
import org.oscim.renderer.overlays.RenderOverlay; import org.oscim.layers.InputLayer;
import org.oscim.view.MapView; import org.oscim.view.MapView;
import android.view.KeyEvent;
import android.view.MotionEvent;
/** /**
* Base class representing an overlay which may be displayed on top of a * Base class representing an overlay which may be displayed on top of a
* {@link MapView}. To add an overlay, subclass this class, create an instance, * {@link MapView}. To add an overlay, subclass this class, create an instance,
@ -34,85 +30,37 @@ import android.view.MotionEvent;
* *
* @author Nicolas Gramlich * @author Nicolas Gramlich
*/ */
public abstract class Overlay { public abstract class Overlay extends InputLayer {
// ===========================================================
// Constants
// ===========================================================
//private static AtomicInteger sOrdinal = new AtomicInteger();
// From Google Maps API
//protected static final float SHADOW_X_SKEW = -0.8999999761581421f;
//protected static final float SHADOW_Y_SCALE = 0.5f;
// ===========================================================
// Fields
// ===========================================================
private boolean mEnabled = true;
private boolean mReceiveEvents = true;
protected final MapView mMapView;
/** RenderOverlay used to draw this layer. To be implemented by sub-classes */
protected RenderOverlay mLayer;
public RenderOverlay getLayer() {
return mLayer;
}
// ===========================================================
// Constructors
// ===========================================================
public Overlay(MapView mapView) { public Overlay(MapView mapView) {
mMapView = mapView; super(mapView);
}
// ===========================================================
// Getter & Setter
// ===========================================================
/**
* Sets whether the Overlay is marked to be enabled. This setting does
* nothing by default, but should be checked before calling draw().
*
* @param pEnabled
* ...
*/
public void setEnabled(boolean pEnabled) {
mEnabled = pEnabled;
} }
/** /**
* Specifies if the Overlay is marked to be enabled. This should be checked * TBD
* before calling draw(). *
* Interface definition for overlays that contain items that can be snapped
* to (for example, when the user invokes a zoom, this could be called
* allowing the user to snap the zoom to an interesting point.)
* *
* @return true if the Overlay is marked enabled, false otherwise
*/ */
public boolean isEnabled() { public interface Snappable {
return mEnabled;
}
/** /**
* Sets whether the Overlay is marked to be receive touch exents. * Checks to see if the given x and y are close enough to an item
* resulting in snapping the current action (e.g. zoom) to the item.
* *
* @param pEnabled * @param x
* ... * The x in screen coordinates.
* @param y
* The y in screen coordinates.
* @param snapPoint
* To be filled with the the interesting point (in screen
* coordinates) that is closest to the given x and y. Can be
* untouched if not snapping.
* @return Whether or not to snap to the interesting point.
*/ */
public void setEnableEvents(boolean pEnabled) { boolean onSnapToItem(int x, int y, PointF snapPoint);
mReceiveEvents = pEnabled;
}
/**
* Specifies if the Overlay is marked to be enabled. This should be checked
* before calling draw().
*
* @return true if the Overlay is marked enabled, false otherwise
*/
public boolean eventsEnabled() {
return mReceiveEvents;
} }
///** ///**
@ -139,256 +87,4 @@ public abstract class Overlay {
//protected final static int getSafeMenuIdSequence(int count) { //protected final static int getSafeMenuIdSequence(int count) {
// return sOrdinal.getAndAdd(count); // return sOrdinal.getAndAdd(count);
//} //}
// ===========================================================
// Methods
// ===========================================================
/**
* Called before each frame render request.
*
* @param mapPosition
* current MapPosition
* @param changed
* true when MapPosition has changed since last call
*/
public void onUpdate(MapPosition mapPosition, boolean changed) {
}
/**
* Override to perform clean up of resources before shutdown. By default
* does nothing.
*/
public void onDetach() {
// FIXME call to this function is not implemented
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param keyCode
* ...
* @param event
* ...
* @return ...
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param keyCode
* ...
* @param event
* ...
* @return ...
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
return false;
}
/**
* <b>You can prevent all(!) other Touch-related events from happening!</b><br />
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onTouchEvent(MotionEvent e) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onTrackballEvent(MotionEvent e) {
return false;
}
/** GestureDetector.OnDoubleTapListener **/
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onDoubleTap(MotionEvent e) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onSingleTapConfirmed(MotionEvent e) {
return false;
}
/** OnGestureListener **/
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onDown(MotionEvent e) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param pEvent1
* ...
* @param pEvent2
* ...
* @param pVelocityX
* ...
* @param pVelocityY
* ...
* @return ...
*/
public boolean onFling(MotionEvent pEvent1, MotionEvent pEvent2,
float pVelocityX, float pVelocityY) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onLongPress(MotionEvent e) {
return false;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param pEvent1
* ...
* @param pEvent2
* ...
* @param pDistanceX
* ...
* @param pDistanceY
* ...
* @return ...
*/
public boolean onScroll(MotionEvent pEvent1, MotionEvent pEvent2,
float pDistanceX, float pDistanceY) {
return false;
}
/**
* @param pEvent
* ...
*/
public void onShowPress(MotionEvent pEvent) {
return;
}
/**
* By default does nothing (<code>return false</code>). If you handled the
* Event, return <code>true</code>, otherwise return <code>false</code>. If
* you returned <code>true</code> none of the following Overlays or the
* underlying {@link MapView} has the chance to handle this event.
*
* @param e
* ...
* @return ...
*/
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
/**
* Interface definition for overlays that contain items that can be snapped
* to (for example, when the user invokes a zoom, this could be called
* allowing the user to snap the zoom to an interesting point.)
*/
public interface Snappable {
/**
* Checks to see if the given x and y are close enough to an item
* resulting in snapping the current action (e.g. zoom) to the item.
*
* @param x
* The x in screen coordinates.
* @param y
* The y in screen coordinates.
* @param snapPoint
* To be filled with the the interesting point (in screen
* coordinates) that is closest to the given x and y. Can be
* untouched if not snapping.
* @return Whether or not to snap to the interesting point.
*/
boolean onSnapToItem(int x, int y, PointF snapPoint);
}
} }

View File

@ -25,6 +25,7 @@ import org.oscim.core.MercatorProjection;
import org.oscim.core.PointD; import org.oscim.core.PointD;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.graphics.Paint.Cap; import org.oscim.graphics.Paint.Cap;
import org.oscim.layers.Layer;
import org.oscim.renderer.GLRenderer.Matrices; import org.oscim.renderer.GLRenderer.Matrices;
import org.oscim.renderer.layer.LineLayer; import org.oscim.renderer.layer.LineLayer;
import org.oscim.renderer.overlays.BasicOverlay; import org.oscim.renderer.overlays.BasicOverlay;
@ -34,7 +35,7 @@ import org.oscim.utils.LineClipper;
import org.oscim.view.MapView; import org.oscim.view.MapView;
/** This class draws a path line in given color. */ /** This class draws a path line in given color. */
public class PathOverlay extends Overlay { public class PathOverlay extends Layer {
/** Stores points, converted to the map projection. */ /** Stores points, converted to the map projection. */
/* package */protected final ArrayList<GeoPoint> mPoints; /* package */protected final ArrayList<GeoPoint> mPoints;

View File

@ -18,8 +18,6 @@ import static android.opengl.GLES20.GL_ARRAY_BUFFER;
import static android.opengl.GLES20.GL_DYNAMIC_DRAW; import static android.opengl.GLES20.GL_DYNAMIC_DRAW;
import static android.opengl.GLES20.GL_ONE; import static android.opengl.GLES20.GL_ONE;
import static android.opengl.GLES20.GL_ONE_MINUS_SRC_ALPHA; import static android.opengl.GLES20.GL_ONE_MINUS_SRC_ALPHA;
import static org.oscim.generator.JobTile.STATE_NEW_DATA;
import static org.oscim.generator.JobTile.STATE_READY;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
@ -31,6 +29,7 @@ import javax.microedition.khronos.opengles.GL10;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.layers.tile.MapTile;
import org.oscim.renderer.layer.Layers; import org.oscim.renderer.layer.Layers;
import org.oscim.renderer.layer.TextureItem; import org.oscim.renderer.layer.TextureItem;
import org.oscim.renderer.overlays.RenderOverlay; import org.oscim.renderer.overlays.RenderOverlay;
@ -62,7 +61,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
static int CACHE_TILES = CACHE_TILES_MAX; static int CACHE_TILES = CACHE_TILES_MAX;
private static MapView mMapView; private static MapView mMapView;
static int screenWidth, screenHeight; public static int screenWidth, screenHeight;
private static MapViewPosition mMapViewPosition; private static MapViewPosition mMapViewPosition;
private static MapPosition mMapPosition; private static MapPosition mMapPosition;
@ -76,6 +75,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private static float[] mBoxCoords; private static float[] mBoxCoords;
public class Matrices { public class Matrices {
// do not modify any of these
public final Matrix4 viewproj = new Matrix4(); public final Matrix4 viewproj = new Matrix4();
public final Matrix4 proj = new Matrix4(); public final Matrix4 proj = new Matrix4();
public final Matrix4 view = new Matrix4(); public final Matrix4 view = new Matrix4();
@ -89,88 +89,14 @@ public class GLRenderer implements GLSurfaceView.Renderer {
//private //private
static float[] mClearColor = null; static float[] mClearColor = null;
static int mQuadIndicesID; public static int mQuadIndicesID;
final static int maxQuads = 64; public final static int maxQuads = 64;
private static boolean mUpdateColor = false; private static boolean mUpdateColor = false;
// drawlock to synchronize Main- and GL-Thread // drawlock to synchronize Main- and GL-Thread
// static ReentrantLock tilelock = new ReentrantLock(); // static ReentrantLock tilelock = new ReentrantLock();
static ReentrantLock drawlock = new ReentrantLock(); public static ReentrantLock drawlock = new ReentrantLock();
// Add additional tiles that serve as placeholer when flipping
// over date-line.
// I dont really like this but cannot think of a better solution:
// the other option would be to run scanbox each time for upload,
// drawing, proxies and text layer. needing to add placeholder only
// happens rarely, unless you live on Fidschi
/* package */static int mNumTileHolder;
/* package */static TileSet mDrawTiles;
// scanline fill class used to check tile visibility
private static ScanBox mScanBox = new ScanBox() {
@Override
void setVisible(int y, int x1, int x2) {
int cnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles;
for (int i = 0; i < cnt; i++) {
MapTile t = tiles[i];
if (t.tileY == y && t.tileX >= x1 && t.tileX < x2)
t.isVisible = true;
}
int xmax = 1 << mZoom;
if (x1 >= 0 && x2 < xmax)
return;
// add placeholder tiles to show both sides
// of date line. a little too complicated...
for (int x = x1; x < x2; x++) {
MapTile holder = null;
MapTile tile = null;
boolean found = false;
if (x >= 0 && x < xmax)
continue;
int xx = x;
if (x < 0)
xx = xmax + x;
else
xx = x - xmax;
if (xx < 0 || xx >= xmax)
continue;
for (int i = cnt; i < cnt + mNumTileHolder; i++)
if (tiles[i].tileX == x && tiles[i].tileY == y) {
found = true;
break;
}
if (found)
continue;
for (int i = 0; i < cnt; i++)
if (tiles[i].tileX == xx && tiles[i].tileY == y) {
tile = tiles[i];
break;
}
if (tile == null)
continue;
holder = new MapTile(x, y, (byte) mZoom);
holder.isVisible = true;
holder.holder = tile;
tile.isVisible = true;
tiles[cnt + mNumTileHolder++] = holder;
}
}
};
/** /**
* @param mapView * @param mapView
@ -204,8 +130,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mUpdateColor = true; mUpdateColor = true;
} }
private static int uploadCnt = 0;
public static boolean uploadLayers(Layers layers, int newSize, public static boolean uploadLayers(Layers layers, int newSize,
boolean addFill) { boolean addFill) {
@ -258,7 +182,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
return true; return true;
} }
private static void checkBufferUsage(boolean force) { public static void checkBufferUsage(boolean force) {
// try to clear some unused vbo when exceding limit // try to clear some unused vbo when exceding limit
if (!force && mBufferMemoryUsage < LIMIT_BUFFERS) { if (!force && mBufferMemoryUsage < LIMIT_BUFFERS) {
@ -300,100 +224,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
} }
} }
private static Object tilelock = new Object();
/** set tile isVisible flag true for tiles that intersect view */
private static void updateTileVisibility() {
MapPosition pos = mMapPosition;
MapTile[] tiles = mDrawTiles.tiles;
// lock tiles while updating isVisible state
synchronized (GLRenderer.tilelock) {
int tileZoom = tiles[0].zoomLevel;
for (int i = 0; i < mDrawTiles.cnt; i++)
tiles[i].isVisible = false;
// count placeholder tiles
mNumTileHolder = 0;
// check visibile tiles
mScanBox.scan(pos.x, pos.y, pos.scale, tileZoom, mBoxCoords);
}
}
private static void uploadTileData(MapTile tile) {
tile.state = STATE_READY;
if (tile.layers == null)
return;
int newSize = tile.layers.getSize();
if (newSize > 0) {
if (tile.layers.vbo == null)
tile.layers.vbo = BufferObject.get(newSize);
if (!uploadLayers(tile.layers, newSize, true)) {
Log.d(TAG, "BUG uploadTileData " + tile + " failed!");
BufferObject.release(tile.layers.vbo);
tile.layers.vbo = null;
tile.layers.clear();
tile.layers = null;
}
}
}
/** compile tile layer data and upload to VBOs */
private static void compileTileLayers(MapTile[] tiles, int tileCnt) {
uploadCnt = 0;
for (int i = 0; i < tileCnt; i++) {
MapTile tile = tiles[i];
if (!tile.isVisible)
continue;
if (tile.state == STATE_READY)
continue;
if (tile.state == STATE_NEW_DATA) {
uploadTileData(tile);
continue;
}
if (tile.holder != null) {
// load tile that is referenced by this holder
if (tile.holder.state == STATE_NEW_DATA)
uploadTileData(tile.holder);
tile.state = tile.holder.state;
continue;
}
// check near relatives than can serve as proxy
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
MapTile rel = tile.rel.parent.tile;
if (rel.state == STATE_NEW_DATA)
uploadTileData(rel);
// dont load child proxies
continue;
}
for (int c = 0; c < 4; c++) {
if ((tile.proxies & 1 << c) == 0)
continue;
MapTile rel = tile.rel.child[c].tile;
if (rel != null && rel.state == STATE_NEW_DATA)
uploadTileData(rel);
}
}
if (uploadCnt > 0)
checkBufferUsage(false);
}
private static void draw() { private static void draw() {
long start = 0; long start = 0;
@ -407,35 +238,14 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mUpdateColor = false; mUpdateColor = false;
} }
// Note: it seems faster to also clear the stencil buffer even
// when not needed. probaly otherwise it is masked out from the
// depth buffer as they share the same memory region afaik
// or for a better reason see OpenGL Insights chapter 23.
GLES20.glDepthMask(true); GLES20.glDepthMask(true);
GLES20.glStencilMask(0xFF); GLES20.glStencilMask(0xFF);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT
| GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT
| GLES20.GL_STENCIL_BUFFER_BIT); | GLES20.GL_STENCIL_BUFFER_BIT);
int serial = 0; boolean tilesChanged = true;
if (mDrawTiles != null) boolean positionChanged = true;
serial = mDrawTiles.serial;
// get current tiles to draw
mDrawTiles = mMapView.getTileManager().getActiveTiles(mDrawTiles);
if (mDrawTiles == null || mDrawTiles.cnt == 0)
return;
boolean tilesChanged = false;
boolean positionChanged = false;
// check if the tiles have changed...
if (serial != mDrawTiles.serial) {
tilesChanged = true;
// FIXME needed?
positionChanged = true;
}
// get current MapPosition, set mBoxCoords (mapping of screen to model // get current MapPosition, set mBoxCoords (mapping of screen to model
// coordinates) // coordinates)
@ -457,38 +267,22 @@ public class GLRenderer implements GLSurfaceView.Renderer {
} }
} }
int tileCnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles;
if (positionChanged)
updateTileVisibility();
tileCnt += mNumTileHolder;
/* prepare tile for rendering */
compileTileLayers(tiles, tileCnt);
tilesChanged |= (uploadCnt > 0);
/* update overlays */ /* update overlays */
RenderOverlay[] overlays = mMapView.getOverlayManager().getRenderLayers(); RenderOverlay[] overlays = mMapView.getOverlayManager().getRenderLayers();
for (int i = 0, n = overlays.length; i < n; i++) for (int i = 0, n = overlays.length; i < n; i++)
overlays[i].update(mMapPosition, positionChanged, tilesChanged, mMatrices); overlays[i].update(mMapPosition, positionChanged, tilesChanged, mMatrices);
/* draw base layer */
TileRenderer.draw(tiles, tileCnt, pos, mMatrices);
/* draw overlays */ /* draw overlays */
for (int i = 0, n = overlays.length; i < n; i++) { for (int i = 0, n = overlays.length; i < n; i++) {
RenderOverlay renderOverlay = overlays[i]; RenderOverlay renderLayer = overlays[i];
if (renderOverlay.newData) { if (renderLayer.newData) {
renderOverlay.compile(); renderLayer.compile();
renderOverlay.newData = false; renderLayer.newData = false;
} }
if (renderOverlay.isReady) if (renderLayer.isReady)
renderOverlay.render(mMapPosition, mMatrices); renderLayer.render(mMapPosition, mMatrices);
} }
if (MapView.debugFrameTime) { if (MapView.debugFrameTime) {
@ -506,44 +300,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
return ((t.tileX % 4) + (t.tileY % 4 * 4) + 1); return ((t.tileX % 4) + (t.tileY % 4 * 4) + 1);
} }
// get a TileSet of currently visible tiles
public static TileSet getVisibleTiles(TileSet td) {
if (mDrawTiles == null)
return td;
// ensure tiles keep visible state
synchronized (GLRenderer.tilelock) {
MapTile[] newTiles = mDrawTiles.tiles;
int cnt = mDrawTiles.cnt;
if (td == null)
td = new TileSet(newTiles.length);
// unlock previous tiles
for (int i = 0; i < td.cnt; i++)
td.tiles[i].unlock();
// lock tiles to not be removed from cache
td.cnt = 0;
for (int i = 0; i < cnt; i++) {
MapTile t = newTiles[i];
if (t.isVisible && t.state == STATE_READY) {
t.lock();
td.tiles[td.cnt++] = t;
}
}
}
return td;
}
public static void releaseTiles(TileSet td) {
for (int i = 0; i < td.cnt; i++) {
td.tiles[i].unlock();
td.tiles[i] = null;
}
td.cnt = 0;
}
@Override @Override
public void onSurfaceChanged(GL10 glUnused, int width, int height) { public void onSurfaceChanged(GL10 glUnused, int width, int height) {
Log.d(TAG, "SurfaceChanged:" + mNewSurface + " " + width + "x" + height); Log.d(TAG, "SurfaceChanged:" + mNewSurface + " " + width + "x" + height);
@ -608,7 +364,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0); GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
mBufferMemoryUsage = 0; mBufferMemoryUsage = 0;
mDrawTiles = null; //mDrawTiles = null;
int numTiles = (screenWidth / (Tile.SIZE / 2) + 2) int numTiles = (screenWidth / (Tile.SIZE / 2) + 2)
* (screenHeight / (Tile.SIZE / 2) + 2); * (screenHeight / (Tile.SIZE / 2) + 2);
@ -624,18 +380,21 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mMapView.redrawMap(true); mMapView.redrawMap(true);
} }
public static void initRenderer() {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// String ext = GLES20.glGetString(GLES20.GL_EXTENSIONS);
// Log.d(TAG, "Extensions: " + ext);
// classes that require GL context for initialization
LineRenderer.init(); LineRenderer.init();
LineTexRenderer.init(); LineTexRenderer.init();
PolygonRenderer.init(); PolygonRenderer.init();
TextureRenderer.init(); TextureRenderer.init();
TextureItem.init(10); TextureItem.init(10);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Log.d(TAG, GLES20.glGetString(GLES20.GL_EXTENSIONS));
// classes that require GL context for initialization
initRenderer();
mNewSurface = true; mNewSurface = true;
} }

View File

@ -1,148 +0,0 @@
/*
* 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.oscim.renderer;
import android.util.Log;
public class QuadTree {
private static String TAG = QuadTree.class.getName();
// pointer to tile 0/0/0
private static QuadTree root;
// parent pointer is used to link pool items
private static QuadTree pool;
public QuadTree parent;
// .... x y
// 0 => 0 0
// 1 => 1 0
// 2 => 0 1
// 3 => 1 1
public final QuadTree[] child = new QuadTree[4];
int refs = 0;
byte id;
public MapTile tile;
static void init() {
pool = null;
root = new QuadTree();
root.parent = root;
}
static boolean remove(MapTile t) {
if (t.rel == null) {
// Bad Things(tm) happened
Log.d(TAG, "BUG already removed " + t);
return true;
}
QuadTree cur = t.rel;
QuadTree next;
for (; cur != root;) {
// keep pointer to parent
next = cur.parent;
cur.refs--;
// if current node has no children
if (cur.refs == 0) {
// unhook from parent
next.child[cur.id] = null;
// add item back to pool
cur.parent = pool;
pool = cur;
}
cur = next;
}
root.refs--;
t.rel.tile = null;
t.rel = null;
return true;
}
static QuadTree add(MapTile tile) {
int x = tile.tileX;
int y = tile.tileY;
int z = tile.zoomLevel;
// if (x < 0 || x >= 1 << z) {
// Log.d(TAG, "invalid position");
// return null;
// }
// if (y < 0 || y >= 1 << z) {
// Log.d(TAG, "invalid position");
// return null;
// }
QuadTree leaf = root;
for (int level = z - 1; level >= 0; level--) {
int id = ((x >> level) & 1) | ((y >> level) & 1) << 1;
leaf.refs++;
QuadTree cur = leaf.child[id];
if (cur != null) {
leaf = cur;
continue;
}
if (pool != null) {
cur = pool;
pool = pool.parent;
} else {
cur = new QuadTree();
}
cur.refs = 0;
cur.id = (byte) id;
cur.parent = leaf;
cur.parent.child[id] = cur;
leaf = cur;
}
leaf.refs++;
leaf.tile = tile;
tile.rel = leaf;
return leaf;
}
static MapTile getTile(int x, int y, int z) {
QuadTree leaf = root;
for (int level = z - 1; level >= 0; level--) {
leaf = leaf.child[((x >> level) & 1) | ((y >> level) & 1) << 1];
if (leaf == null)
return null;
if (level == 0) {
return leaf.tile;
}
}
return null;
}
}

View File

@ -78,7 +78,7 @@ public abstract class ScanBox {
protected int mZoom; protected int mZoom;
abstract void setVisible(int y, int x1, int x2); protected abstract void setVisible(int y, int x1, int x2);
public void scan(double x, double y, double scale, int zoom, float[] box) { public void scan(double x, double y, double scale, int zoom, float[] box) {
mZoom = zoom; mZoom = zoom;

View File

@ -20,12 +20,13 @@ import java.nio.ShortBuffer;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.generator.JobTile; import org.oscim.layers.tile.JobTile;
import org.oscim.layers.tile.MapTile;
import org.oscim.layers.tile.TileRenderLayer;
import org.oscim.layers.tile.TileSet;
import org.oscim.renderer.GLRenderer; import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.GLRenderer.Matrices; import org.oscim.renderer.GLRenderer.Matrices;
import org.oscim.renderer.GLState; import org.oscim.renderer.GLState;
import org.oscim.renderer.MapTile;
import org.oscim.renderer.TileSet;
import org.oscim.renderer.layer.ExtrusionLayer; import org.oscim.renderer.layer.ExtrusionLayer;
import org.oscim.utils.GlUtils; import org.oscim.utils.GlUtils;
import org.oscim.view.MapView; import org.oscim.view.MapView;
@ -39,8 +40,11 @@ import android.util.Log;
public class ExtrusionOverlay extends RenderOverlay { public class ExtrusionOverlay extends RenderOverlay {
private final static String TAG = ExtrusionOverlay.class.getName(); private final static String TAG = ExtrusionOverlay.class.getName();
public ExtrusionOverlay(MapView mapView) { private final TileRenderLayer mTileLayer;
public ExtrusionOverlay(MapView mapView, org.oscim.layers.tile.TileRenderLayer tileRenderLayer) {
super(mapView); super(mapView);
mTileLayer = tileRenderLayer;
} }
private static int[] shaderProgram = new int[2]; private static int[] shaderProgram = new int[2];
@ -92,7 +96,10 @@ public class ExtrusionOverlay extends RenderOverlay {
} }
int ready = 0; int ready = 0;
mTileSet = mMapView.getTileManager().getActiveTiles(mTileSet); mTileSet = mTileLayer.getVisibleTiles(mTileSet);
if (mTileSet == null)
return;
MapTile[] tiles = mTileSet.tiles; MapTile[] tiles = mTileSet.tiles;
// FIXME just release tiles in this case // FIXME just release tiles in this case
if (mAlpha == 0 || curPos.zoomLevel < 16) { if (mAlpha == 0 || curPos.zoomLevel < 16) {
@ -135,11 +142,12 @@ public class ExtrusionOverlay extends RenderOverlay {
for (int i = 0; i < mTileSet.cnt; i++) { for (int i = 0; i < mTileSet.cnt; i++) {
if (!tiles[i].isVisible) if (!tiles[i].isVisible)
continue; continue;
MapTile t = tiles[i]; MapTile t = tiles[i];
for (byte j = 0; j < 4; j++) { for (byte j = 0; j < 4; j++) {
if ((t.proxies & (1 << j)) != 0) { if ((t.proxies & (1 << j)) != 0) {
MapTile c = t.rel.child[j].tile; MapTile c = t.rel.get(j);
el = getLayer(c); el = getLayer(c);
if (el == null || !el.compiled) if (el == null || !el.compiled)

View File

@ -32,18 +32,19 @@ import java.util.HashMap;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.generator.JobTile;
import org.oscim.graphics.Color; import org.oscim.graphics.Color;
import org.oscim.graphics.Paint.Cap; import org.oscim.graphics.Paint.Cap;
import org.oscim.layers.tile.JobTile;
import org.oscim.layers.tile.MapTile;
import org.oscim.layers.tile.TileRenderLayer;
import org.oscim.layers.tile.TileSet;
import org.oscim.renderer.BufferObject; import org.oscim.renderer.BufferObject;
import org.oscim.renderer.GLRenderer; import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.GLRenderer.Matrices; import org.oscim.renderer.GLRenderer.Matrices;
import org.oscim.renderer.GLState; import org.oscim.renderer.GLState;
import org.oscim.renderer.LineRenderer; import org.oscim.renderer.LineRenderer;
import org.oscim.renderer.MapTile;
import org.oscim.renderer.PolygonRenderer; import org.oscim.renderer.PolygonRenderer;
import org.oscim.renderer.TextureRenderer; import org.oscim.renderer.TextureRenderer;
import org.oscim.renderer.TileSet;
import org.oscim.renderer.layer.Layer; import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.Layers; import org.oscim.renderer.layer.Layers;
import org.oscim.renderer.layer.LineLayer; import org.oscim.renderer.layer.LineLayer;
@ -199,11 +200,13 @@ public class TextOverlay extends BasicOverlay {
private float mSquareRadius; private float mSquareRadius;
private int mRelabelCnt; private int mRelabelCnt;
private final TileRenderLayer mTileLayer;
public TextOverlay(MapView mapView) { public TextOverlay(MapView mapView, TileRenderLayer baseLayer) {
super(mapView); super(mapView);
mMapViewPosition = mapView.getMapViewPosition();
mMapViewPosition = mapView.getMapViewPosition();
mTileLayer = baseLayer;
layers.textureLayers = new TextLayer(); layers.textureLayers = new TextLayer();
mTmpLayer = new TextLayer(); mTmpLayer = new TextLayer();
mActiveTiles = new HashMap<MapTile, LabelTile>(); mActiveTiles = new HashMap<MapTile, LabelTile>();
@ -350,7 +353,9 @@ public class TextOverlay extends BasicOverlay {
return false; return false;
// get current tiles // get current tiles
mTileSet = GLRenderer.getVisibleTiles(mTileSet); mTileSet = mTileLayer.getVisibleTiles(mTileSet);
if (mTileSet == null)
return false;
if (mTileSet.cnt == 0) if (mTileSet.cnt == 0)
return false; return false;
@ -605,7 +610,7 @@ public class TextOverlay extends BasicOverlay {
tl.labels = null; tl.labels = null;
// remove tile locks // remove tile locks
GLRenderer.releaseTiles(mTileSet); mTileLayer.releaseTiles(mTileSet);
// pass new labels for rendering // pass new labels for rendering
synchronized (this) { synchronized (this) {

View File

@ -117,6 +117,8 @@ public class RenderThemeHandler extends DefaultHandler {
private int mLevel; private int mLevel;
private RenderTheme mRenderTheme; private RenderTheme mRenderTheme;
private final Stack<Rule> mRuleStack = new Stack<Rule>(); private final Stack<Rule> mRuleStack = new Stack<Rule>();
private final HashMap<String, RenderInstruction> tmpStyleHash =
new HashMap<String, RenderInstruction>(10);
@Override @Override
public void endDocument() { public void endDocument() {
@ -148,8 +150,6 @@ public class RenderThemeHandler extends DefaultHandler {
Log.d(TAG, exception.getMessage()); Log.d(TAG, exception.getMessage());
} }
private static HashMap<String, RenderInstruction> tmpStyleHash =
new HashMap<String, RenderInstruction>(10);
@Override @Override
public void startElement(String uri, String localName, String qName, public void startElement(String uri, String localName, String qName,

View File

@ -21,7 +21,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.PointF; import org.oscim.core.PointF;
import org.oscim.overlay.Overlay; import org.oscim.layers.InputLayer;
import org.oscim.layers.Layer;
import org.oscim.overlay.Overlay.Snappable; import org.oscim.overlay.Overlay.Snappable;
import org.oscim.renderer.overlays.RenderOverlay; import org.oscim.renderer.overlays.RenderOverlay;
@ -32,45 +33,45 @@ import android.view.GestureDetector.OnGestureListener;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
public class LayerManager extends AbstractList<Overlay> implements OnGestureListener, public class LayerManager extends AbstractList<Layer> implements OnGestureListener,
OnDoubleTapListener { OnDoubleTapListener {
private final GestureDetector mGestureDetector; private final GestureDetector mGestureDetector;
private final CopyOnWriteArrayList<Overlay> mOverlayList; private final CopyOnWriteArrayList<Layer> mLayerList;
LayerManager(Context context) { LayerManager(Context context) {
mOverlayList = new CopyOnWriteArrayList<Overlay>(); mLayerList = new CopyOnWriteArrayList<Layer>();
mGestureDetector = new GestureDetector(context, this); mGestureDetector = new GestureDetector(context, this);
mGestureDetector.setOnDoubleTapListener(this); mGestureDetector.setOnDoubleTapListener(this);
} }
@Override @Override
public synchronized Overlay get(final int pIndex) { public synchronized Layer get(final int pIndex) {
return mOverlayList.get(pIndex); return mLayerList.get(pIndex);
} }
@Override @Override
public synchronized int size() { public synchronized int size() {
return mOverlayList.size(); return mLayerList.size();
} }
@Override @Override
public synchronized void add(final int pIndex, final Overlay pElement) { public synchronized void add(final int pIndex, final Layer pElement) {
mOverlayList.add(pIndex, pElement); mLayerList.add(pIndex, pElement);
mDirtyOverlays = true; mDirtyLayers = true;
} }
@Override @Override
public synchronized Overlay remove(final int pIndex) { public synchronized Layer remove(final int pIndex) {
mDirtyOverlays = true; mDirtyLayers = true;
return mOverlayList.remove(pIndex); return mLayerList.remove(pIndex);
} }
@Override @Override
public synchronized Overlay set(final int pIndex, final Overlay pElement) { public synchronized Layer set(final int pIndex, final Layer pElement) {
mDirtyOverlays = true; mDirtyLayers = true;
return mOverlayList.set(pIndex, pElement); return mLayerList.set(pIndex, pElement);
} }
public boolean handleMotionEvent(MotionEvent e) { public boolean handleMotionEvent(MotionEvent e) {
@ -84,59 +85,68 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
return false; return false;
} }
private boolean mDirtyOverlays; private boolean mDirtyLayers;
private RenderOverlay[] mDrawLayers; private RenderOverlay[] mDrawLayers;
public RenderOverlay[] getRenderLayers() { public RenderOverlay[] getRenderLayers() {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
return mDrawLayers; return mDrawLayers;
} }
public void onDetach() { public void onDetach() {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (Layer o : mLayers)
o.onDetach(); o.onDetach();
} }
Overlay[] mOverlays; Layer[] mLayers;
InputLayer[] mInputLayer;
private synchronized void updateOverlays() { private synchronized void updateLayers() {
if (!mDirtyOverlays) if (!mDirtyLayers)
return; return;
mOverlays = new Overlay[mOverlayList.size()]; mLayers = new Layer[mLayerList.size()];
int numRenderLayers = 0; int numRenderLayers = 0;
int numInputLayers = 0;
for (int i = 0, n = mOverlayList.size(); i < n; i++) { for (int i = 0, n = mLayerList.size(); i < n; i++) {
Overlay o = mOverlayList.get(i); Layer o = mLayerList.get(i);
if (o.getLayer() != null) if (o.getLayer() != null)
numRenderLayers++; numRenderLayers++;
mOverlays[n - i - 1] = o; if (o instanceof InputLayer)
numInputLayers++;
mLayers[n - i - 1] = o;
} }
mDrawLayers = new RenderOverlay[numRenderLayers]; mDrawLayers = new RenderOverlay[numRenderLayers];
mInputLayer = new InputLayer[numInputLayers];
for (int i = 0, cnt = 0, n = mOverlayList.size(); i < n; i++) { for (int i = 0, cntR = 0, cntI = 0, n = mLayerList.size(); i < n; i++) {
Overlay o = mOverlayList.get(i); Layer o = mLayerList.get(i);
RenderOverlay l = o.getLayer(); RenderOverlay l = o.getLayer();
if (l != null) if (l != null)
mDrawLayers[cnt++] = l; mDrawLayers[cntR++] = l;
if (o instanceof InputLayer)
mInputLayer[cntI++] = (InputLayer)o;
} }
mDirtyOverlays = false; mDirtyLayers = false;
} }
public boolean onTouchEvent(final MotionEvent event) { public boolean onTouchEvent(final MotionEvent event) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onTouchEvent(event)) if (o.onTouchEvent(event))
return true; return true;
@ -144,10 +154,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
} }
public boolean onKeyDown(final int keyCode, final KeyEvent event) { public boolean onKeyDown(final int keyCode, final KeyEvent event) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onKeyDown(keyCode, event)) if (o.onKeyDown(keyCode, event))
return true; return true;
@ -155,10 +165,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
} }
public boolean onKeyUp(final int keyCode, final KeyEvent event) { public boolean onKeyUp(final int keyCode, final KeyEvent event) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onKeyUp(keyCode, event)) if (o.onKeyUp(keyCode, event))
return true; return true;
@ -166,10 +176,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
} }
public boolean onTrackballEvent(final MotionEvent event) { public boolean onTrackballEvent(final MotionEvent event) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onTrackballEvent(event)) if (o.onTrackballEvent(event))
return true; return true;
@ -177,10 +187,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
} }
public boolean onSnapToItem(final int x, final int y, final PointF snapPoint) { public boolean onSnapToItem(final int x, final int y, final PointF snapPoint) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o instanceof Snappable) if (o instanceof Snappable)
if (((Snappable) o).onSnapToItem(x, y, snapPoint)) if (((Snappable) o).onSnapToItem(x, y, snapPoint))
return true; return true;
@ -192,10 +202,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
@Override @Override
public boolean onDoubleTap(final MotionEvent e) { public boolean onDoubleTap(final MotionEvent e) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onDoubleTap(e)) if (o.onDoubleTap(e))
return true; return true;
@ -204,10 +214,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
@Override @Override
public boolean onDoubleTapEvent(final MotionEvent e) { public boolean onDoubleTapEvent(final MotionEvent e) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onDoubleTapEvent(e)) if (o.onDoubleTapEvent(e))
return true; return true;
@ -216,10 +226,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
@Override @Override
public boolean onSingleTapConfirmed(final MotionEvent e) { public boolean onSingleTapConfirmed(final MotionEvent e) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onSingleTapConfirmed(e)) if (o.onSingleTapConfirmed(e))
return true; return true;
@ -230,10 +240,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
@Override @Override
public boolean onDown(final MotionEvent pEvent) { public boolean onDown(final MotionEvent pEvent) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onDown(pEvent)) if (o.onDown(pEvent))
return true; return true;
@ -243,10 +253,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
@Override @Override
public boolean onFling(final MotionEvent pEvent1, final MotionEvent pEvent2, public boolean onFling(final MotionEvent pEvent1, final MotionEvent pEvent2,
final float pVelocityX, final float pVelocityY) { final float pVelocityX, final float pVelocityY) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onFling(pEvent1, pEvent2, pVelocityX, pVelocityY)) if (o.onFling(pEvent1, pEvent2, pVelocityX, pVelocityY))
return true; return true;
@ -255,10 +265,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
@Override @Override
public void onLongPress(final MotionEvent pEvent) { public void onLongPress(final MotionEvent pEvent) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onLongPress(pEvent)) if (o.onLongPress(pEvent))
return; return;
} }
@ -266,10 +276,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
@Override @Override
public boolean onScroll(final MotionEvent pEvent1, final MotionEvent pEvent2, public boolean onScroll(final MotionEvent pEvent1, final MotionEvent pEvent2,
final float pDistanceX, final float pDistanceY) { final float pDistanceX, final float pDistanceY) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onScroll(pEvent1, pEvent2, pDistanceX, pDistanceY)) if (o.onScroll(pEvent1, pEvent2, pDistanceX, pDistanceY))
return true; return true;
@ -278,20 +288,20 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
@Override @Override
public void onShowPress(final MotionEvent pEvent) { public void onShowPress(final MotionEvent pEvent) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
o.onShowPress(pEvent); o.onShowPress(pEvent);
} }
@Override @Override
public boolean onSingleTapUp(final MotionEvent pEvent) { public boolean onSingleTapUp(final MotionEvent pEvent) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (InputLayer o : mInputLayer)
if (o.onSingleTapUp(pEvent)) if (o.onSingleTapUp(pEvent))
return true; return true;
@ -299,52 +309,62 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
} }
public void onUpdate(MapPosition mapPosition, boolean changed) { public void onUpdate(MapPosition mapPosition, boolean changed) {
if (mDirtyOverlays) if (mDirtyLayers)
updateOverlays(); updateLayers();
for (Overlay o : mOverlays) for (Layer l : mLayers)
o.onUpdate(mapPosition, changed); l.onUpdate(mapPosition, changed);
} }
public void destroy() {
if (mDirtyLayers)
updateLayers();
for (Layer l : mLayers){
l.destroy();
}
}
// /** // /**
// * Gets the optional TilesOverlay class. // * Gets the optional TilesLayer class.
// * // *
// * @return the tilesOverlay // * @return the tilesLayer
// */ // */
// public TilesOverlay getTilesOverlay() { // public TilesLayer getTilesLayer() {
// return mTilesOverlay; // return mTilesLayer;
// } // }
// //
// /** // /**
// * Sets the optional TilesOverlay class. If set, this overlay will be // * Sets the optional TilesLayer class. If set, this overlay will be
// drawn before all other // drawn before all other
// * overlays and will not be included in the editable list of overlays and // * overlays and will not be included in the editable list of overlays and
// can't be cleared // can't be cleared
// * except by a subsequent call to setTilesOverlay(). // * except by a subsequent call to setTilesLayer().
// * // *
// * @param tilesOverlay // * @param tilesLayer
// * the tilesOverlay to set // * the tilesLayer to set
// */ // */
// public void setTilesOverlay(final TilesOverlay tilesOverlay) { // public void setTilesLayer(final TilesLayer tilesLayer) {
// mTilesOverlay = tilesOverlay; // mTilesLayer = tilesLayer;
// } // }
// public void onDraw(final Canvas c, final MapView pMapView) { // public void onDraw(final Canvas c, final MapView pMapView) {
// // if ((mTilesOverlay != null) && mTilesOverlay.isEnabled()) { // // if ((mTilesLayer != null) && mTilesLayer.isEnabled()) {
// // mTilesOverlay.draw(c, pMapView, true); // // mTilesLayer.draw(c, pMapView, true);
// // } // // }
// // // //
// // if ((mTilesOverlay != null) && mTilesOverlay.isEnabled()) { // // if ((mTilesLayer != null) && mTilesLayer.isEnabled()) {
// // mTilesOverlay.draw(c, pMapView, false); // // mTilesLayer.draw(c, pMapView, false);
// // } // // }
// //
// for (final Overlay overlay : mOverlayList) { // for (final Layer overlay : mLayerList) {
// if (overlay.isEnabled()) { // if (overlay.isEnabled()) {
// overlay.draw(c, pMapView, true); // overlay.draw(c, pMapView, true);
// } // }
// } // }
// //
// for (final Overlay overlay : mOverlayList) { // for (final Layer overlay : mLayerList) {
// if (overlay.isEnabled()) { // if (overlay.isEnabled()) {
// overlay.draw(c, pMapView, false); // overlay.draw(c, pMapView, false);
// } // }
@ -355,10 +375,10 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
// ** Options Menu **// // ** Options Menu **//
// public void setOptionsMenusEnabled(final boolean pEnabled) { // public void setOptionsMenusEnabled(final boolean pEnabled) {
// for (final Overlay overlay : mOverlayList) { // for (final Layer overlay : mLayerList) {
// if ((overlay instanceof IOverlayMenuProvider) // if ((overlay instanceof ILayerMenuProvider)
// && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled()) { // && ((ILayerMenuProvider) overlay).isOptionsMenuEnabled()) {
// ((IOverlayMenuProvider) overlay).setOptionsMenuEnabled(pEnabled); // ((ILayerMenuProvider) overlay).setOptionsMenuEnabled(pEnabled);
// } // }
// } // }
// } // }
@ -367,19 +387,19 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
// menuIdOffset, // menuIdOffset,
// final MapView mapView) { // final MapView mapView) {
// boolean result = true; // boolean result = true;
// for (final Overlay overlay : this.overlaysReversed()) { // for (final Layer overlay : this.overlaysReversed()) {
// if ((overlay instanceof IOverlayMenuProvider) // if ((overlay instanceof ILayerMenuProvider)
// && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled()) { // && ((ILayerMenuProvider) overlay).isOptionsMenuEnabled()) {
// result &= ((IOverlayMenuProvider) overlay).onCreateOptionsMenu(pMenu, // result &= ((ILayerMenuProvider) overlay).onCreateOptionsMenu(pMenu,
// menuIdOffset, // menuIdOffset,
// mapView); // mapView);
// } // }
// } // }
// //
// if ((mTilesOverlay != null) && (mTilesOverlay instanceof // if ((mTilesLayer != null) && (mTilesLayer instanceof
// IOverlayMenuProvider) // ILayerMenuProvider)
// && ((IOverlayMenuProvider) mTilesOverlay).isOptionsMenuEnabled()) { // && ((ILayerMenuProvider) mTilesLayer).isOptionsMenuEnabled()) {
// result &= mTilesOverlay.onCreateOptionsMenu(pMenu, menuIdOffset, // result &= mTilesLayer.onCreateOptionsMenu(pMenu, menuIdOffset,
// mapView); // mapView);
// } // }
// //
@ -389,18 +409,18 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
// public boolean onPrepareOptionsMenu(final Menu pMenu, final int // public boolean onPrepareOptionsMenu(final Menu pMenu, final int
// menuIdOffset, // menuIdOffset,
// final MapView mapView) { // final MapView mapView) {
// for (final Overlay overlay : this.overlaysReversed()) { // for (final Layer overlay : this.overlaysReversed()) {
// if ((overlay instanceof IOverlayMenuProvider) // if ((overlay instanceof ILayerMenuProvider)
// && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled()) { // && ((ILayerMenuProvider) overlay).isOptionsMenuEnabled()) {
// ((IOverlayMenuProvider) overlay).onPrepareOptionsMenu(pMenu, // ((ILayerMenuProvider) overlay).onPrepareOptionsMenu(pMenu,
// menuIdOffset, mapView); // menuIdOffset, mapView);
// } // }
// } // }
// //
// if ((mTilesOverlay != null) && (mTilesOverlay instanceof // if ((mTilesLayer != null) && (mTilesLayer instanceof
// IOverlayMenuProvider) // ILayerMenuProvider)
// && ((IOverlayMenuProvider) mTilesOverlay).isOptionsMenuEnabled()) { // && ((ILayerMenuProvider) mTilesLayer).isOptionsMenuEnabled()) {
// mTilesOverlay.onPrepareOptionsMenu(pMenu, menuIdOffset, mapView); // mTilesLayer.onPrepareOptionsMenu(pMenu, menuIdOffset, mapView);
// } // }
// //
// return true; // return true;
@ -409,20 +429,20 @@ public class LayerManager extends AbstractList<Overlay> implements OnGestureList
// public boolean onOptionsItemSelected(final MenuItem item, final int // public boolean onOptionsItemSelected(final MenuItem item, final int
// menuIdOffset, // menuIdOffset,
// final MapView mapView) { // final MapView mapView) {
// for (final Overlay overlay : this.overlaysReversed()) { // for (final Layer overlay : this.overlaysReversed()) {
// if ((overlay instanceof IOverlayMenuProvider) // if ((overlay instanceof ILayerMenuProvider)
// && ((IOverlayMenuProvider) overlay).isOptionsMenuEnabled() // && ((ILayerMenuProvider) overlay).isOptionsMenuEnabled()
// && ((IOverlayMenuProvider) overlay).onOptionsItemSelected(item, // && ((ILayerMenuProvider) overlay).onOptionsItemSelected(item,
// menuIdOffset, // menuIdOffset,
// mapView)) { // mapView)) {
// return true; // return true;
// } // }
// } // }
// //
// if ((mTilesOverlay != null) // if ((mTilesLayer != null)
// && (mTilesOverlay instanceof IOverlayMenuProvider) // && (mTilesLayer instanceof ILayerMenuProvider)
// && ((IOverlayMenuProvider) mTilesOverlay).isOptionsMenuEnabled() // && ((ILayerMenuProvider) mTilesLayer).isOptionsMenuEnabled()
// && ((IOverlayMenuProvider) mTilesOverlay).onOptionsItemSelected(item, // && ((ILayerMenuProvider) mTilesLayer).onOptionsItemSelected(item,
// menuIdOffset, // menuIdOffset,
// mapView)) { // mapView)) {
// return true; // return true;

View File

@ -14,11 +14,8 @@
*/ */
package org.oscim.view; package org.oscim.view;
import java.io.FileNotFoundException;
import org.oscim.core.GeoPoint; import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.theme.InternalRenderTheme;
import android.app.Activity; import android.app.Activity;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -78,7 +75,7 @@ public abstract class MapActivity extends Activity {
editor.putInt(KEY_LONGITUDE, geoPoint.longitudeE6); editor.putInt(KEY_LONGITUDE, geoPoint.longitudeE6);
editor.putFloat(KEY_MAP_SCALE, (float)mapPosition.scale); editor.putFloat(KEY_MAP_SCALE, (float)mapPosition.scale);
editor.putString(KEY_THEME, mMapView.getRenderTheme()); //editor.putString(KEY_THEME, mMapView.getRenderTheme());
editor.commit(); editor.commit();
} }
@ -121,21 +118,21 @@ public abstract class MapActivity extends Activity {
mMapView.getMapViewPosition().setMapPosition(mapPosition); mMapView.getMapViewPosition().setMapPosition(mapPosition);
} }
String theme = sharedPreferences.getString(KEY_THEME, //String theme = sharedPreferences.getString(KEY_THEME,
InternalRenderTheme.DEFAULT.name()); // InternalRenderTheme.DEFAULT.name());
if (theme.startsWith("/")) { // if (theme.startsWith("/")) {
try { // try {
mapView.setRenderTheme(theme); // mapView.setRenderTheme(theme);
} catch (FileNotFoundException e) { // } catch (FileNotFoundException e) {
mapView.setRenderTheme(InternalRenderTheme.DEFAULT); // mapView.setRenderTheme(InternalRenderTheme.DEFAULT);
} // }
} else { // } else {
try { // try {
mapView.setRenderTheme(InternalRenderTheme.valueOf(theme)); // mapView.setRenderTheme(InternalRenderTheme.valueOf(theme));
} catch (IllegalArgumentException e) { // } catch (IllegalArgumentException e) {
mapView.setRenderTheme(InternalRenderTheme.DEFAULT); // mapView.setRenderTheme(InternalRenderTheme.DEFAULT);
} // }
} // }
} }
} }

View File

@ -15,41 +15,21 @@
*/ */
package org.oscim.view; package org.oscim.view;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.oscim.core.BoundingBox; import org.oscim.core.BoundingBox;
import org.oscim.core.GeoPoint; import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.database.IMapDatabase;
import org.oscim.database.MapDatabaseFactory;
import org.oscim.database.MapDatabases;
import org.oscim.database.MapInfo;
import org.oscim.database.MapOptions; import org.oscim.database.MapOptions;
import org.oscim.database.OpenResult; import org.oscim.layers.Layer;
import org.oscim.generator.JobQueue; import org.oscim.layers.tile.TileGenerator;
import org.oscim.generator.JobTile; import org.oscim.layers.tile.TileLayer;
import org.oscim.generator.MapWorker;
import org.oscim.generator.TileGenerator;
import org.oscim.overlay.BuildingOverlay; import org.oscim.overlay.BuildingOverlay;
import org.oscim.overlay.LabelingOverlay; import org.oscim.overlay.LabelingOverlay;
import org.oscim.overlay.Overlay; import org.oscim.overlay.Overlay;
import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.GLView; import org.oscim.renderer.GLView;
import org.oscim.renderer.TileManager;
import org.oscim.theme.ExternalRenderTheme;
import org.oscim.theme.InternalRenderTheme;
import org.oscim.theme.RenderTheme;
import org.oscim.theme.RenderThemeHandler;
import org.oscim.theme.Theme;
import org.oscim.utils.AndroidUtils; import org.oscim.utils.AndroidUtils;
import org.xml.sax.SAXException;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
@ -68,43 +48,28 @@ public class MapView extends RelativeLayout {
public static final boolean debugFrameTime = false; public static final boolean debugFrameTime = false;
public static final boolean testRegionZoom = false; public static final boolean testRegionZoom = false;
private static final boolean debugDatabase = false;
public boolean mRotationEnabled = false; public boolean mRotationEnabled = false;
public boolean mCompassEnabled = false; public boolean mCompassEnabled = false;
public boolean enablePagedFling = false; public boolean enablePagedFling = false;
private final GLView mGLView;
private final LayerManager mLayerManager;
private final MapViewPosition mMapViewPosition; private final MapViewPosition mMapViewPosition;
private final MapPosition mMapPosition; private final MapPosition mMapPosition;
//private final MapZoomControls mMapZoomControls;
private final Compass mCompass; private final Compass mCompass;
private final TileManager mTileManager;
private final LayerManager mLayerManager;
final GLView mGLView;
private final JobQueue mJobQueue;
// TODO use 1 download and 1 generator thread instead
private final MapWorker mMapWorkers[];
private final int mNumMapWorkers = 4;
private MapOptions mMapOptions;
private IMapDatabase mMapDatabase;
private String mRenderTheme;
private DebugSettings mDebugSettings; private DebugSettings mDebugSettings;
private boolean mClearMap;
private int mWidth; private int mWidth;
private int mHeight; private int mHeight;
// FIXME: keep until old pbmap reader is removed // FIXME: keep until old pbmap reader is removed
public static boolean enableClosePolygons = false; public static boolean enableClosePolygons = false;
public final float dpi; public static float dpi;
/** /**
* @param context * @param context
@ -152,21 +117,12 @@ public class MapView extends RelativeLayout {
mCompass = new Compass(mapActivity, this); mCompass = new Compass(mapActivity, this);
mJobQueue = new JobQueue();
mTileManager = new TileManager(this);
mGLView = new GLView(context, this); mGLView = new GLView(context, this);
mMapWorkers = new MapWorker[mNumMapWorkers];
mDebugSettings = new DebugSettings(); mDebugSettings = new DebugSettings();
TileGenerator.setDebugSettings(mDebugSettings);
for (int i = 0; i < mNumMapWorkers; i++) { // FIXME
TileGenerator tileGenerator = new TileGenerator(); TileGenerator.setDebugSettings(mDebugSettings);
mMapWorkers[i] = new MapWorker(i, mJobQueue, tileGenerator, mTileManager);
mMapWorkers[i].start();
}
mapActivity.registerMapView(this); mapActivity.registerMapView(this);
@ -176,7 +132,19 @@ public class MapView extends RelativeLayout {
addView(mGLView, params); addView(mGLView, params);
mLayerManager.add(new MapEventLayer(this)); requestRedraw();
}
public TileLayer setBaseMap(MapOptions options){
TileLayer baseLayer = new TileLayer(this);
baseLayer.setMapDatabase(options);
mLayerManager.add(0,new MapEventLayer(this));
mLayerManager.add(1,baseLayer);
//mMapZoomControls = new MapZoomControls(mapActivity, this); //mMapZoomControls = new MapZoomControls(mapActivity, this);
//mMapZoomControls.setShowMapZoomControls(true); //mMapZoomControls.setShowMapZoomControls(true);
@ -184,41 +152,14 @@ public class MapView extends RelativeLayout {
//mLayerManager.add(new GenericOverlay(this, new GridOverlay(this))); //mLayerManager.add(new GenericOverlay(this, new GridOverlay(this)));
mLayerManager.add(new BuildingOverlay(this)); mLayerManager.add(new BuildingOverlay(this, baseLayer.getTileLayer()));
mLayerManager.add(new LabelingOverlay(this)); mLayerManager.add(new LabelingOverlay(this, baseLayer.getTileLayer()));
//mLayerManager.add(new GenericOverlay(this, new TileOverlay(this))); return baseLayer;
//mLayerManager.add(new GenericOverlay(this, new CustomOverlay(this)));
//mLayerManager.add(new MapLensOverlay(this));
//PathOverlay path = new PathOverlay(this, Color.RED);
//path.addGreatCircle(new GeoPoint(53.1, 8.8), new GeoPoint(53.1, -110.0));
//mLayerManager.add(path);
//path = new PathOverlay(this, Color.GREEN);
//path.addGreatCircle(new GeoPoint(53.1, 140), new GeoPoint(53.1, -110.0));
//mLayerManager.add(path);
//mLayerManager.add(new GenericOverlay(this, new AtlasTest(this)));
clearMap();
} }
void destroy() { void destroy() {
mTileManager.destroy(); mLayerManager.destroy();
for (MapWorker mapWorker : mMapWorkers) {
mapWorker.pause();
mapWorker.interrupt();
mapWorker.getTileGenerator().getMapDatabase().close();
try {
mapWorker.join(10000);
} catch (InterruptedException e) {
// restore the interrupted status
Thread.currentThread().interrupt();
}
}
} }
private boolean mPausing = false; private boolean mPausing = false;
@ -226,18 +167,12 @@ public class MapView extends RelativeLayout {
void onPause() { void onPause() {
mPausing = true; mPausing = true;
Log.d(TAG, "onPause");
mJobQueue.clear();
mapWorkersPause(true);
if (this.mCompassEnabled) if (this.mCompassEnabled)
mCompass.disable(); mCompass.disable();
} }
void onResume() { void onResume() {
Log.d(TAG, "onResume");
mapWorkersProceed();
if (this.mCompassEnabled) if (this.mCompassEnabled)
mCompass.enable(); mCompass.enable();
@ -247,7 +182,7 @@ public class MapView extends RelativeLayout {
public void onStop() { public void onStop() {
Log.d(TAG, "onStop"); Log.d(TAG, "onStop");
//mTileManager.destroy(); //mLayerManager.destroy();
} }
@Override @Override
@ -264,9 +199,6 @@ public class MapView extends RelativeLayout {
int oldWidth, int oldHeight) { int oldWidth, int oldHeight) {
Log.d(TAG, "onSizeChanged: " + width + "x" + height); Log.d(TAG, "onSizeChanged: " + width + "x" + height);
mJobQueue.clear();
mapWorkersPause(true);
super.onSizeChanged(width, height, oldWidth, oldHeight); super.onSizeChanged(width, height, oldWidth, oldHeight);
mWidth = width; mWidth = width;
@ -274,9 +206,6 @@ public class MapView extends RelativeLayout {
if (width != 0 && height != 0) if (width != 0 && height != 0)
mMapViewPosition.setViewport(width, height); mMapViewPosition.setViewport(width, height);
clearMap();
mapWorkersProceed();
} }
public void render() { public void render() {
@ -315,6 +244,24 @@ public class MapView extends RelativeLayout {
return mRotationEnabled; return mRotationEnabled;
} }
boolean mWaitRedraw;
Runnable mRedrawRequest = new Runnable() {
@Override
public void run() {
mWaitRedraw = false;
redrawMap(true);
}
};
public void requestRedraw(){
if (!mWaitRedraw){
mWaitRedraw = true;
post(mRedrawRequest);
}
}
/** /**
* Calculates all necessary tiles and adds jobs accordingly. * Calculates all necessary tiles and adds jobs accordingly.
* *
@ -324,33 +271,27 @@ public class MapView extends RelativeLayout {
if (mPausing || mWidth == 0 || mHeight == 0) if (mPausing || mWidth == 0 || mHeight == 0)
return; return;
if (forceRedraw) boolean changed = false;
if (forceRedraw){
render(); render();
changed = true;
if (mClearMap) {
mTileManager.init(mWidth, mHeight);
mClearMap = false;
// make sure mMapPosition will be updated
mMapPosition.zoomLevel = -1;
// TODO clear overlays
} }
// if (mClearMap) {
// mTileManager.init(mWidth, mHeight);
// mClearMap = false;
//
// // make sure mMapPosition will be updated
// mMapPosition.zoomLevel = -1;
//
// // TODO clear overlays
// }
boolean changed = mMapViewPosition.getMapPosition(mMapPosition); changed |= mMapViewPosition.getMapPosition(mMapPosition);
// required when not changed? // required when not changed?
if (AndroidUtils.currentThreadIsUiThread()) if (AndroidUtils.currentThreadIsUiThread())
mLayerManager.onUpdate(mMapPosition, changed); mLayerManager.onUpdate(mMapPosition, changed);
if (changed) {
mTileManager.update(mMapPosition);
}
}
private void clearMap() {
// clear tile and overlay data before next draw
mClearMap = true;
} }
/** /**
@ -360,7 +301,7 @@ public class MapView extends RelativeLayout {
public void setDebugSettings(DebugSettings debugSettings) { public void setDebugSettings(DebugSettings debugSettings) {
mDebugSettings = debugSettings; mDebugSettings = debugSettings;
TileGenerator.setDebugSettings(debugSettings); TileGenerator.setDebugSettings(debugSettings);
clearMap(); //clearMap();
} }
/** /**
@ -370,184 +311,10 @@ public class MapView extends RelativeLayout {
return mDebugSettings; return mDebugSettings;
} }
public Map<String, String> getMapOptions() {
return mMapOptions;
}
public MapPosition getMapFileCenter() {
if (mMapDatabase == null)
return null;
MapInfo mapInfo = mMapDatabase.getMapInfo();
if (mapInfo == null)
return null;
GeoPoint startPos = mapInfo.startPosition;
if (startPos == null)
startPos = mapInfo.mapCenter;
if (startPos == null)
startPos = new GeoPoint(0, 0);
MapPosition mapPosition = new MapPosition();
mapPosition.setPosition(startPos);
if (mapInfo.startZoomLevel == null)
mapPosition.setZoomLevel(12);
else
mapPosition.setZoomLevel((mapInfo.startZoomLevel).byteValue());
return mapPosition;
}
public void setMapPosition(MapPosition mapPosition) { public void setMapPosition(MapPosition mapPosition) {
mMapViewPosition.setMapPosition(mapPosition); mMapViewPosition.setMapPosition(mapPosition);
} }
/**
* Sets the MapDatabase for this MapView.
*
* @param options
* the new MapDatabase options.
* @return true if MapDatabase changed
*/
public boolean setMapDatabase(MapOptions options) {
if (debugDatabase)
return false;
Log.i(TAG, "setMapDatabase: " + options.db.name());
if (mMapOptions != null && mMapOptions.equals(options))
return true;
mapWorkersPause(true);
mJobQueue.clear();
mMapOptions = options;
mMapDatabase = null;
for (int i = 0; i < mNumMapWorkers; i++) {
MapWorker mapWorker = mMapWorkers[i];
IMapDatabase mapDatabase = MapDatabaseFactory
.createMapDatabase(options.db);
OpenResult result = mapDatabase.open(options);
if (result != OpenResult.SUCCESS) {
Log.d(TAG, "failed open db: " + result.getErrorMessage());
}
TileGenerator tileGenerator = mapWorker.getTileGenerator();
tileGenerator.setMapDatabase(mapDatabase);
// TODO this could be done in a cleaner way..
if (mMapDatabase == null)
mMapDatabase = mapDatabase;
}
if (options.db == MapDatabases.OSCIMAP_READER ||
options.db == MapDatabases.MAP_READER)
MapView.enableClosePolygons = true;
else
MapView.enableClosePolygons = false;
clearMap();
mapWorkersProceed();
return true;
}
public String getRenderTheme() {
return mRenderTheme;
}
/**
* Sets the internal theme which is used for rendering the map.
*
* @param internalRenderTheme
* the internal rendering theme.
* @return ...
* @throws IllegalArgumentException
* if the supplied internalRenderTheme is null.
*/
public boolean setRenderTheme(InternalRenderTheme internalRenderTheme) {
if (internalRenderTheme == null) {
throw new IllegalArgumentException("render theme must not be null");
}
if (internalRenderTheme.name() == mRenderTheme)
return true;
boolean ret = setRenderTheme((Theme) internalRenderTheme);
if (ret) {
mRenderTheme = internalRenderTheme.name();
}
clearMap();
return ret;
}
/**
* Sets the theme file which is used for rendering the map.
*
* @param renderThemePath
* the path to the XML file which defines the rendering theme.
* @throws IllegalArgumentException
* if the supplied internalRenderTheme is null.
* @throws FileNotFoundException
* if the supplied file does not exist, is a directory or cannot
* be read.
*/
public void setRenderTheme(String renderThemePath) throws FileNotFoundException {
if (renderThemePath == null) {
throw new IllegalArgumentException("render theme path must not be null");
}
boolean ret = setRenderTheme(new ExternalRenderTheme(renderThemePath));
if (ret) {
mRenderTheme = renderThemePath;
}
clearMap();
}
private boolean setRenderTheme(Theme theme) {
mapWorkersPause(true);
InputStream inputStream = null;
try {
inputStream = theme.getRenderThemeAsStream();
RenderTheme t = RenderThemeHandler.getRenderTheme(inputStream);
t.scaleTextSize(1 + (dpi / 240 - 1) * 0.5f);
// FIXME
GLRenderer.setRenderTheme(t);
TileGenerator.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 {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
mapWorkersProceed();
}
return false;
}
/** /**
* Sets the center of the MapView and triggers a redraw. * Sets the center of the MapView and triggers a redraw.
* *
@ -567,45 +334,6 @@ public class MapView extends RelativeLayout {
return mMapViewPosition; return mMapViewPosition;
} }
/**
* add jobs and remember MapWorkers that stuff needs to be done
*
* @param jobs
* tile jobs
*/
public void addJobs(JobTile[] jobs) {
if (jobs == null) {
mJobQueue.clear();
return;
}
mJobQueue.setJobs(jobs);
for (int i = 0; i < mNumMapWorkers; i++) {
MapWorker m = mMapWorkers[i];
synchronized (m) {
m.notify();
}
}
}
private void mapWorkersPause(boolean wait) {
for (MapWorker mapWorker : mMapWorkers) {
if (!mapWorker.isPausing())
mapWorker.pause();
}
if (wait) {
for (MapWorker mapWorker : mMapWorkers) {
if (!mapWorker.isPausing())
mapWorker.awaitPausing();
}
}
}
private void mapWorkersProceed() {
for (MapWorker mapWorker : mMapWorkers)
mapWorker.proceed();
}
/** /**
* You can add/remove/reorder your Overlays using the List of * You can add/remove/reorder your Overlays using the List of
* {@link Overlay}. The first (index 0) Overlay gets drawn first, the one * {@link Overlay}. The first (index 0) Overlay gets drawn first, the one
@ -613,7 +341,7 @@ public class MapView extends RelativeLayout {
* *
* @return ... * @return ...
*/ */
public List<Overlay> getOverlays() { public List<Layer> getOverlays() {
return this.getOverlayManager(); return this.getOverlayManager();
} }
@ -621,10 +349,6 @@ public class MapView extends RelativeLayout {
return mLayerManager; return mLayerManager;
} }
public TileManager getTileManager() {
return mTileManager;
}
/** /**
* @return estimated visible axis aligned bounding box * @return estimated visible axis aligned bounding box
*/ */