implement render further

git-svn-id: https://osmand.googlecode.com/svn/trunk@490 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-09-06 22:11:37 +00:00
parent 476754caeb
commit c3472fcee1
21 changed files with 416 additions and 295 deletions

View file

@ -16,23 +16,30 @@ public class ToDoConstants {
// railway( station, subway?) - issue 17
// 86. Allow to add/edit custom tags to POI objects.
// 87. Use network availability for defining loading tiles from internet.
// 88. Implement show gpx track from folder and navigate using gpx track.
// 89. Transport redesign UI (enable run from context menu, switch go to goal/not) !
// TODO small improvements for release :
// 1. If select vector map, notice if there are no loaded maps.
// TODO Improvements:
// 1! VELCOM
// 2. rotate map gps without location
// 3! Transport redesign call UI (enable context menu call, switch go to goal/not)
// 4. recalculating route when location is far from !
// 4. recalculating route when location is far from ! (error)
// 5. keyboard (issue 43 )?
// 6. Do not upload empty files (transport, poi... ).
// 7. Implement auto-delete from site (done, should be ported from C#)
// 8. In all places verify to use float lat/lon improve disk space for indexes !!!
// 13! Support multiple database for map rendering
// 8. In all places verify to use float lat/lon improve usage indexes !!!
// + 9. Render map on bitmap in another thread
// + 10. Sort objects before render (according layering)
// 11!! Investigate ResourceManager close methods and clear cache when Map switches !!!
// 12! When switch to map check that indexes were loaded !!
// 11. Move JUnidecode on client save space for some indexes
// + 11!! Investigate ResourceManager close methods and clear cache when Map switches !!! (MAP SWITCH, update settings)
// + 12! When switch to map check that indexes were loaded !!
// + 14. Rotate vector map
// 15. Draw layers -> icons -> text. See intersects of double streets.
// 11. Move JUnidecode on client save space for some indexes adn
// 12. Fix : find proper location for streets ! centralize them (when create index)?
// TODO Check
@ -49,12 +56,13 @@ public class ToDoConstants {
// Not clear if it is really needed
// 69. Add phone information to POI
// 70. Show building numbers over map (require changing address index - index 2 more columns lat/lon for fast search)
// 66. Transport routing (show next stop, total distance, show stop get out, voice) (needed ?).
// 85. Enable on/off screen for bike navigation (?)
// 83. Add monitoring service to send locations to internet (?)
// DONE ANDROID :
// 70. Show building numbers over map (require changing address index - index 2 more columns lat/lon for fast search).
// (Not needed, because of vector rendering)
// 82. Rotate map according compass
// 85. Remove context menu on long press map ! Accumulate actions and show label (+)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="vector_data">Векторные osm карты</string>
<string name="transport_context_menu">Искать транспорт на остановке</string>
<string name="point_on_map">Точка на карте\n Ш {0,number,#.####} Д {1,number,#.####}</string>
<string name="osb_bug_name">Bug</string>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="vector_data">Vector osm maps</string>
<string name="transport_context_menu">Search transport at stop</string>
<string name="point_on_map">Point on map\n Lat {0,number,#.####} lon {1,number,#.####}</string>
<string name="osb_bug_name">Bug</string>

View file

@ -322,7 +322,13 @@ public class OsmandSettings {
}
// this value string is synchronized with settings_pref.xml preference name
public static final String MAP_VECTOR_DATA = "map_vector_data"; //$NON-NLS-1$
public static final String MAP_TILE_SOURCES = "map_tile_sources"; //$NON-NLS-1$
public static boolean isUsingMapVectorData(Context ctx){
SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
return prefs.getBoolean(MAP_VECTOR_DATA, false);
}
public static ITileSource getMapTileSource(Context ctx) {
SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
@ -358,7 +364,7 @@ public class OsmandSettings {
return new TileSourceManager.TileSourceTemplate(dir.getName(), url);
}
}
}
return TileSourceManager.getMapnikSource();
}

View file

@ -21,7 +21,7 @@ import net.osmand.data.preparation.MapTileDownloader.IMapDownloaderCallback;
import net.osmand.map.ITileSource;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils;
import net.osmand.render.RenderMapsRepositories;
import net.osmand.render.MapRenderRepositories;
import net.osmand.views.POIMapLayer;
import org.apache.commons.logging.Log;
@ -49,6 +49,7 @@ public class ResourceManager {
public static final String TRANSPORT_PATH = APP_DIR + IndexConstants.TRANSPORT_INDEX_DIR;
public static final String TILES_PATH = APP_DIR+"tiles/"; //$NON-NLS-1$
public static final String TEMP_SOURCE_TO_LOAD = "temp"; //$NON-NLS-1$
public static final String VECTOR_MAP = "#vector_map"; //$NON-NLS-1$
public static final int LIMIT_TRANSPORT = 200;
@ -82,14 +83,14 @@ public class ResourceManager {
protected final Map<String, TransportIndexRepository> transportRepositories = new LinkedHashMap<String, TransportIndexRepository>();
protected final RenderMapsRepositories renderer ;
protected final MapRenderRepositories renderer ;
public final AsyncLoadingThread asyncLoadingTiles = new AsyncLoadingThread();
public ResourceManager(Context context) {
this.context = context;
this.renderer = new RenderMapsRepositories(context);
this.renderer = new MapRenderRepositories(context);
// TODO start/stop this thread when needed?
asyncLoadingTiles.start();
dirWithTiles = new File(Environment.getExternalStorageDirectory(), TILES_PATH);
@ -526,14 +527,14 @@ public class ResourceManager {
}
////////////////////////////////////////////// Working with map ////////////////////////////////////////////////
public void updateRendererIfNeeded(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom){
if(!renderer.updateMapIsNotNeeded(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom)){
public void updateRendererIfNeeded(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, float rotate){
if(!renderer.updateMapIsNotNeeded(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, rotate)){
asyncLoadingTiles.requestToLoadMap(
new MapLoadRequest(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom));
new MapLoadRequest(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, rotate));
}
}
public RenderMapsRepositories getRenderer() {
public MapRenderRepositories getRenderer() {
return renderer;
}
@ -584,16 +585,16 @@ public class ResourceManager {
}
public synchronized void setMapSource(ITileSource source){
public synchronized void updateMapSource(boolean useVectorMap, ITileSource source){
log.info("Clear cache with new source " + cacheOfImages.size()); //$NON-NLS-1$
ArrayList<String> list = new ArrayList<String>(cacheOfImages.keySet());
// remove first images (as we think they are older)
for (int i = 0; i < list.size(); i ++) {
Bitmap bmp = cacheOfImages.remove(list.get(i));
if(bmp != null){
bmp.recycle();
}
}
renderer.clearCache();
if(source == null || source.getBitDensity() == 0){
maxImgCacheSize = 32;
} else {
@ -681,15 +682,17 @@ public class ResourceManager {
public final double leftLongitude;
public final double rightLongitude;
public final int zoom;
public final float rotate;
public MapLoadRequest(double topLatitude, double leftLongitude,
double bottomLatitude, double rightLongitude, int zoom) {
double bottomLatitude, double rightLongitude, int zoom, float rotate) {
super();
this.bottomLatitude = bottomLatitude;
this.leftLongitude = leftLongitude;
this.rightLongitude = rightLongitude;
this.topLatitude = topLatitude;
this.zoom = zoom;
this.rotate = rotate;
}
}
@ -732,7 +735,7 @@ public class ResourceManager {
} else if(req instanceof MapLoadRequest){
if(!mapLoaded){
MapLoadRequest r = (MapLoadRequest) req;
renderer.loadMap(r.topLatitude, r.leftLongitude, r.bottomLatitude, r.rightLongitude, r.zoom);
renderer.loadMap(r.topLatitude, r.leftLongitude, r.bottomLatitude, r.rightLongitude, r.zoom, r.rotate);
mapLoaded = true;
}
}

View file

@ -241,7 +241,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
mapView.addLayer(contextMenuLayer, 9);
// 10. route info layer
routeInfoLayer = new RouteInfoLayer(routingHelper, (LinearLayout) findViewById(R.id.RouteLayout));
mapView.addLayer(routeInfoLayer, 9);
mapView.addLayer(routeInfoLayer, 10);
@ -707,28 +707,31 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
trafficLayer.setVisible(OsmandSettings.isShowingYandexTraffic(this));
}
private void updateMapSource(ITileSource newSource){
private void updateMapSource(){
boolean vectorData = OsmandSettings.isUsingMapVectorData(this);
ITileSource newSource = OsmandSettings.getMapTileSource(this);
if(mapView.getMap() instanceof SQLiteTileSource){
((SQLiteTileSource)mapView.getMap()).closeDB();
}
((OsmandApplication)getApplication()).getResourceManager().setMapSource(newSource);
mapView.setMap(newSource);
((OsmandApplication)getApplication()).getResourceManager().updateMapSource(vectorData, newSource);
mapView.setMap(vectorData ? null : newSource);
rendererLayer.setVisible(vectorData);
}
@Override
protected void onResume() {
super.onResume();
// TODO not commit it
rendererLayer.setVisible(true);
if(OsmandSettings.getMapOrientation(this) != getRequestedOrientation()){
setRequestedOrientation(OsmandSettings.getMapOrientation(this));
}
currentScreenOrientation = getWindow().getWindowManager().getDefaultDisplay().getOrientation();
ITileSource source = OsmandSettings.getMapTileSource(this);
if(!Algoritms.objectEquals(mapView.getMap(), source)){
updateMapSource(source);
boolean showTiles = !OsmandSettings.isUsingMapVectorData(this);
ITileSource source = showTiles ? OsmandSettings.getMapTileSource(this) : null;
if (showTiles != !rendererLayer.isVisible() || !Algoritms.objectEquals(mapView.getMap(), source)) {
updateMapSource();
}
updateApplicationModeSettings();
@ -1280,17 +1283,27 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
}
private void selectMapLayer(){
Map<String, String> entriesMap = SettingsActivity.getTileSourceEntries();
Map<String, String> entriesMap = SettingsActivity.getTileSourceEntries(this);
Builder builder = new AlertDialog.Builder(this);
final ArrayList<String> keys = new ArrayList<String>(entriesMap.keySet());
builder.setItems(entriesMap.values().toArray(new String[entriesMap.size()]), new DialogInterface.OnClickListener(){
String[] items = new String[entriesMap.size() + 1];
items[0] = getString(R.string.vector_data);
int i = 1;
for(String it : entriesMap.values()){
items[i++] = it;
}
builder.setItems(items, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
Editor edit = OsmandSettings.getWriteableEditor(MapActivity.this);
edit.putString(OsmandSettings.MAP_TILE_SOURCES, keys.get(which));
if(which == 0){
edit.putBoolean(OsmandSettings.MAP_VECTOR_DATA, true);
} else {
edit.putBoolean(OsmandSettings.MAP_VECTOR_DATA, false);
edit.putString(OsmandSettings.MAP_TILE_SOURCES, keys.get(which - 1));
}
edit.commit();
updateMapSource(OsmandSettings.getMapTileSource(MapActivity.this));
mapView.refreshMap();
updateMapSource();
}
});

View file

@ -45,6 +45,7 @@ public class OsmandApplication extends Application {
public void onCreate(){
super.onCreate();
manager = new ResourceManager(this);
routingHelper = new RoutingHelper(OsmandSettings.getApplicationMode(OsmandApplication.this), OsmandApplication.this, player);
uiHandler = new Handler();
startApplication();
}
@ -88,6 +89,7 @@ public class OsmandApplication extends Application {
public String initCommandPlayer(){
if(player == null){
player = new CommandPlayer(OsmandApplication.this);
routingHelper.getVoiceRouter().setPlayer(player);
}
return player.init();
}
@ -111,7 +113,7 @@ public class OsmandApplication extends Application {
warnings.add(w);
}
}
routingHelper = new RoutingHelper(OsmandSettings.getApplicationMode(OsmandApplication.this), OsmandApplication.this, player);
SavingTrackHelper helper = new SavingTrackHelper(OsmandApplication.this);
if (helper.hasDataToSave()) {
startDialog.startTask(getString(R.string.saving_gpx_tracks), -1);

View file

@ -1,6 +1,8 @@
package net.osmand.activities;
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@ -43,6 +45,7 @@ import android.preference.Preference.OnPreferenceClickListener;
import android.widget.Toast;
public class SettingsActivity extends PreferenceActivity implements OnPreferenceChangeListener, OnPreferenceClickListener {
private final static String VECTOR_MAP = "#VECTOR_MAP"; //$NON-NLS-1$
private class BooleanPreference {
private final boolean defValue;
@ -308,10 +311,12 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
maxLevelToDownload.setValue(OsmandSettings.getMaximumLevelToDownloadTile(this)+""); //$NON-NLS-1$
Map<String, String> entriesMap = getTileSourceEntries();
entries = new String[entriesMap.size()];
valueEntries = new String[entriesMap.size()];
int ki = 0;
Map<String, String> entriesMap = getTileSourceEntries(this);
entries = new String[entriesMap.size() + 1];
valueEntries = new String[entriesMap.size() + 1];
valueEntries[0] = VECTOR_MAP;
entries[0] = getString(R.string.vector_data);
int ki = 1;
for(Map.Entry<String, String> es : entriesMap.entrySet()){
entries[ki] = es.getValue();
valueEntries[ki] = es.getKey();
@ -320,8 +325,10 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
tileSourcePreference.setEntries(entries);
tileSourcePreference.setEntryValues(valueEntries);
tileSourcePreference.setValue(OsmandSettings.getMapTileSourceName(this));
String mapName = " " +OsmandSettings.getMapTileSourceName(this); //$NON-NLS-1$
String value = OsmandSettings.isUsingMapVectorData(this)? VECTOR_MAP : OsmandSettings.getMapTileSourceName(this);
String mapName = " " + (OsmandSettings.isUsingMapVectorData(this) ? getString(R.string.vector_data) : //$NON-NLS-1$
OsmandSettings.getMapTileSourceName(this));
tileSourcePreference.setValue(value);
String summary = tileSourcePreference.getSummary().toString();
if (summary.lastIndexOf(':') != -1) {
summary = summary.substring(0, summary.lastIndexOf(':') + 1);
@ -329,17 +336,31 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
tileSourcePreference.setSummary(summary + mapName);
}
public static Map<String, String> getTileSourceEntries(){
public static Map<String, String> getTileSourceEntries(Context ctx){
Map<String, String> map = new LinkedHashMap<String, String>();
File dir = new File(Environment.getExternalStorageDirectory(), ResourceManager.TILES_PATH);
if (dir != null && dir.canRead()) {
for (File f : dir.listFiles()) {
if (f.getName().endsWith(SQLiteTileSource.EXT)) {
String n = f.getName();
map.put(f.getName(), n.substring(0, n.lastIndexOf('.')));
} else if(f.isDirectory() && !f.getName().equals(ResourceManager.TEMP_SOURCE_TO_LOAD)){
map.put(f.getName(), f.getName());
File[] files = dir.listFiles();
Arrays.sort(files, new Comparator<File>(){
@Override
public int compare(File object1, File object2) {
if(object1.lastModified() > object2.lastModified()){
return -1;
} else if(object1.lastModified() == object2.lastModified()){
return 0;
}
return 1;
}
});
if (files != null) {
for (File f : files) {
if (f.getName().endsWith(SQLiteTileSource.EXT)) {
String n = f.getName();
map.put(f.getName(), n.substring(0, n.lastIndexOf('.')));
} else if (f.isDirectory() && !f.getName().equals(ResourceManager.TEMP_SOURCE_TO_LOAD)) {
map.put(f.getName(), f.getName());
}
}
}
}
@ -440,13 +461,19 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
edit.commit();
((OsmandApplication)getApplication()).initCommandPlayer();
} else if (preference == tileSourcePreference) {
edit.putString(OsmandSettings.MAP_TILE_SOURCES, (String) newValue);
if(VECTOR_MAP.equals((String) newValue)){
edit.putBoolean(OsmandSettings.MAP_VECTOR_DATA, true);
} else {
edit.putString(OsmandSettings.MAP_TILE_SOURCES, (String) newValue);
edit.putBoolean(OsmandSettings.MAP_VECTOR_DATA, false);
}
edit.commit();
String summary = tileSourcePreference.getSummary().toString();
if (summary.lastIndexOf(':') != -1) {
summary = summary.substring(0, summary.lastIndexOf(':') + 1);
}
summary += " " + OsmandSettings.getMapTileSourceName(this); //$NON-NLS-1$
}
summary += " " + (OsmandSettings.isUsingMapVectorData(this) ? getString(R.string.vector_data) : //$NON-NLS-1$
OsmandSettings.getMapTileSourceName(this));
tileSourcePreference.setSummary(summary);
}

View file

@ -20,9 +20,9 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.RectF;
public class RenderMapsRepositories {
public class MapRenderRepositories {
private final static Log log = LogUtil.getLog(RenderMapsRepositories.class);
private final static Log log = LogUtil.getLog(MapRenderRepositories.class);
private final Context context;
private Connection conn;
private PreparedStatement pStatement;
@ -42,7 +42,7 @@ public class RenderMapsRepositories {
public RenderMapsRepositories(Context context){
public MapRenderRepositories(Context context){
this.context = context;
this.renderer = new OsmandRenderer(context);
}
@ -54,7 +54,6 @@ public class RenderMapsRepositories {
public boolean initializeNewResource(final IProgress progress, File file) {
long start = System.currentTimeMillis();
try {
// TODO should support multiple db
if (conn != null) {
// close previous db
conn.close();
@ -117,10 +116,20 @@ public class RenderMapsRepositories {
/**
* @return true if no need to reevaluate map
*/
public boolean updateMapIsNotNeeded(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom){
public boolean updateMapIsNotNeeded(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, float rotate){
if (conn == null) {
return true;
}
boolean inside = insideBox(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom);
if(rotate < 0){
rotate += 360;
}
return inside && Math.abs(rotate - cRotate) < 30;
}
private boolean insideBox(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom) {
boolean inside = cTopLatitude >= topLatitude && cLeftLongitude <= leftLongitude && cRightLongitude >= rightLongitude
&& cBottomLatitude <= bottomLatitude && cZoom == zoom;
return inside;
@ -134,53 +143,60 @@ public class RenderMapsRepositories {
" WHERE ? < maxLat AND ? > minLat AND maxLon > ? AND minLon < ?)"; //$NON-NLS-1$
public synchronized void loadMap(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom) {
cBottomLatitude = bottomLatitude - (topLatitude - bottomLatitude) / 2;
cTopLatitude = topLatitude + (topLatitude - bottomLatitude) / 2;
cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude);
cRightLongitude = rightLongitude + (rightLongitude - leftLongitude);
cZoom = zoom;
log.info(String.format(
"BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", cBottomLatitude, cTopLatitude, cLeftLongitude, cRightLongitude, cZoom)); //$NON-NLS-1$
long now = System.currentTimeMillis();
if(pStatement == null){
return;
}
try {
pStatement.setDouble(1, cBottomLatitude);
pStatement.setDouble(2, cTopLatitude);
pStatement.setDouble(3, cLeftLongitude);
pStatement.setDouble(4, cRightLongitude);
ResultSet result = pStatement.executeQuery();
List<MapRenderObject> local = new LinkedList<MapRenderObject>();
try {
int count = 0;
while (result.next()) {
long id = result.getLong(1);
MapRenderObject obj = new MapRenderObject(id);
obj.setData(result.getBytes(2));
obj.setName(result.getString(3));
obj.setType(result.getInt(4));
count++;
local.add(obj);
}
public synchronized void loadMap(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, float rotate) {
boolean inside = insideBox(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom);
cRotate = rotate < 0 ? rotate + 360 : rotate;
if (!inside) {
cBottomLatitude = bottomLatitude - (topLatitude - bottomLatitude) / 2;
cTopLatitude = topLatitude + (topLatitude - bottomLatitude) / 2;
cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude);
cRightLongitude = rightLongitude + (rightLongitude - leftLongitude);
cZoom = zoom;
cObjects = local;
log.info(String.format("Search has been done in %s ms. %s results were found.", System.currentTimeMillis() - now, count)); //$NON-NLS-1$
} finally {
result.close();
log
.info(String
.format(
"BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", cBottomLatitude, cTopLatitude, cLeftLongitude, cRightLongitude, cZoom)); //$NON-NLS-1$
long now = System.currentTimeMillis();
if (pStatement == null) {
return;
}
try {
pStatement.setDouble(1, cBottomLatitude);
pStatement.setDouble(2, cTopLatitude);
pStatement.setDouble(3, cLeftLongitude);
pStatement.setDouble(4, cRightLongitude);
ResultSet result = pStatement.executeQuery();
List<MapRenderObject> local = new LinkedList<MapRenderObject>();
try {
int count = 0;
while (result.next()) {
long id = result.getLong(1);
MapRenderObject obj = new MapRenderObject(id);
obj.setData(result.getBytes(2));
obj.setName(result.getString(3));
obj.setType(result.getInt(4));
count++;
local.add(obj);
}
cObjects = local;
log.info(String
.format("Search has been done in %s ms. %s results were found.", System.currentTimeMillis() - now, count)); //$NON-NLS-1$
} finally {
result.close();
}
} catch (java.sql.SQLException e) {
log.debug("Search failed", e); //$NON-NLS-1$
}
} catch (java.sql.SQLException e) {
log.debug("Search failed", e); //$NON-NLS-1$
}
// create new instance to distinguish that cache was changed
RectF newLoc = new RectF((float)cLeftLongitude, (float)cTopLatitude, (float)cRightLongitude, (float)cBottomLatitude);
Bitmap bmp = renderer.generateNewBitmap(newLoc, cObjects, cZoom, 0);
Bitmap bmp = renderer.generateNewBitmap(newLoc, cObjects, cZoom, cRotate);
Bitmap oldBmp = this.bmp;
this.bmp = bmp;
cachedWaysLoc = newLoc;
@ -198,10 +214,12 @@ public class RenderMapsRepositories {
public synchronized void clearCache() {
cObjects.clear();
cBottomLatitude = cLeftLongitude = cRightLongitude = cTopLatitude = cRotate = cZoom = 0;
if(bmp != null){
bmp.recycle();
bmp = null;
}
cachedWaysLoc = new RectF();
}
}

View file

@ -27,6 +27,7 @@ import android.graphics.Bitmap.Config;
import android.graphics.Paint.Align;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.util.FloatMath;
public class OsmandRenderer implements Comparator<MapRenderObject> {
private static final Log log = LogUtil.getLog(OsmandRenderer.class);
@ -39,7 +40,6 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
/// Colors
private int clFillScreen = Color.rgb(241, 238, 232);
private int clPoint = Color.rgb(200, 200, 200);
private int clTrunkRoad = Color.rgb(128,155,192);
private int clMotorwayRoad = Color.rgb(168, 218, 168);
private int clPrimaryRoad = Color.rgb(235, 152, 154);
@ -106,6 +106,7 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
bmp = Bitmap.createBitmap((int) ((rightX - leftX) * 256), (int) ((bottomY - topY) * 256), Config.RGB_565);
Canvas cv = new Canvas(bmp);
cv.drawRect(0, 0, bmp.getWidth(), bmp.getHeight(), paintFillWhite);
cv.rotate(-rotate);
for (MapRenderObject w : objects) {
draw(w, cv, leftX, topY, zoom, rotate);
}
@ -122,23 +123,43 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
if(MapRenderingTypes.isHighway(obj.getType())){
drawHighway(obj, canvas, leftTileX, topTileY, zoom, rotate);
} else {
// TODO
}
} else {
PointF center = drawPolygon(obj, canvas, leftTileX, topTileY, zoom);
PointF center = drawPolygon(obj, canvas, leftTileX, topTileY, zoom, rotate);
if(center != null){
int typeT = MapRenderingTypes.getPolygonPointType(obj.getType());
int subT = MapRenderingTypes.getPolygonPointSubType(obj.getType());
if(typeT > 0 && subT > 0){
drawPointBitmap(canvas, zoom, center.x, center.y, typeT, subT);
drawPointBitmap(canvas, center.x, center.y, typeT, subT, zoom);
}
}
}
}
public float calcDiffPixelY(float dTileX, float dTileY, float rotate){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.sin(rad) * dTileX + FloatMath.cos(rad) * dTileY) * 256f ;
}
public float calcDiffPixelX(float dTileX, float dTileY, float rotate){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.cos(rad) * dTileX - FloatMath.sin(rad) * dTileY) * 256f ;
}
// suppose that render works in one thread! Otherwise should be done anyway
private PointF TEMP_POINT = new PointF();
private PointF calcPoint(double leftTileX, double topTileY, float latitude, float longitude, int zoom, float rotate){
float dTileX = (float) (MapUtils.getTileNumberX(zoom, longitude) - leftTileX);
float dTileY = (float) (MapUtils.getTileNumberY(zoom, latitude) - topTileY);
TEMP_POINT.set(calcDiffPixelX(dTileX, dTileY, rotate), calcDiffPixelY(dTileX, dTileY, rotate));
return TEMP_POINT;
}
private PointF drawPolygon(MapRenderObject obj, Canvas canvas, double leftTileX, double topTileY, int zoom) {
private PointF drawPolygon(MapRenderObject obj, Canvas canvas, double leftTileX, double topTileY, int zoom, float rotate) {
Paint paint = paintFill;
float xText = 0;
float yText = 0;
@ -192,15 +213,16 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
paint.setColor(color);
for (int i = 0; i < obj.getPointsLength(); i++) {
float x = (float) ((MapUtils.getTileNumberX(zoom, obj.getPointLongitude(i)) - leftTileX) * 256f);
float y = (float) ((MapUtils.getTileNumberY(zoom, obj.getPointLatitude(i)) - topTileY) * 256f);
xText += x;
yText += y;
float lon = obj.getPointLongitude(i);
float lat = obj.getPointLatitude(i);
PointF p = calcPoint(leftTileX, topTileY, lat, lon, zoom, rotate);
xText += p.x;
yText += p.y;
if (path == null) {
path = new Path();
path.moveTo(x, y);
path.moveTo(p.x, p.y);
} else {
path.lineTo(x, y);
path.lineTo(p.x, p.y);
}
}
@ -211,12 +233,10 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
String name = obj.getName();
if(name != null){
boolean accept = true;
if(zoom <= 15){
boolean accept = zoom > 17;
if(zoom > 15){
accept = name.length() < 4;
} else if(zoom < 17){
accept = name.length() < 6;
} else if(zoom < 18){
} else if(zoom > 16){
accept = name.length() < 8;
}
if(accept){
@ -230,129 +250,29 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
private void drawPoint(MapRenderObject obj, Canvas canvas, double leftTileX, double topTileY, int zoom, float rotate){
if (zoom > 15) {
float x = (float) ((MapUtils.getTileNumberX(zoom, obj.getPointLongitude(0)) - leftTileX) * 256f);
float y = (float) ((MapUtils.getTileNumberY(zoom, obj.getPointLatitude(0)) - topTileY) * 256f);
float lon = obj.getPointLongitude(0);
float lat = obj.getPointLatitude(0);
PointF p = calcPoint(leftTileX, topTileY, lat, lon, zoom, rotate);
int subType = MapRenderingTypes.getPointSubType(obj.getType());
int type = MapRenderingTypes.getObjectType(obj.getType());
drawPointBitmap(canvas, zoom, x, y, type, subType);
drawPointBitmap(canvas, p.x, p.y, type, subType, zoom);
}
}
private void drawPointBitmap(Canvas canvas, int zoom, float x, float y, int type, int subType) {
int resId = 0;
if(type == MapRenderingTypes.HIGHWAY){
if (zoom > 16) {
if(subType == 38){
resId = R.drawable.h_traffic_light;
}
}
} else if(type == MapRenderingTypes.AMENITY_OTHER){
if (zoom > 16) {
switch (subType) {
case 10:
resId = R.drawable.h_police;
break;
case 18:
resId = R.drawable.h_toilets;
break;
case 11:
resId = R.drawable.h_postbox;
break;
case 12:
resId = R.drawable.h_postoffice;
break;
}
}
} else if(type == MapRenderingTypes.SHOP){
if (zoom > 15) {
switch (subType) {
case 27:
case 65:
case 53:
resId = R.drawable.h_shop_supermarket;
break;
}
}
if (zoom > 16) {
switch (subType) {
case 31:
resId = R.drawable.h_shop_hairdresser;
break;
case 48:
resId = R.drawable.h_shop_butcher;
break;
case 42:
resId = R.drawable.h_shop_bakery;
break;
case 20:
resId = R.drawable.h_shop_diy;
break;
case 16:
resId = R.drawable.h_shop_convenience;
break;
case 13:
resId = R.drawable.h_shop_clothes;
break;
}
}
} else if(type == MapRenderingTypes.AMENITY_SUSTENANCE){
// done
if (zoom > 15) {
switch (subType) {
case 1:
resId = R.drawable.h_restaurant;
break;
case 2:
resId = R.drawable.h_cafe;
break;
case 4:
resId = R.drawable.h_fast_food;
break;
case 5:
case 6:
case 7:
resId = R.drawable.h_bar;
break;
case 8:
resId = R.drawable.h_food_drinkingtap;
break;
}
}
} else if(type == MapRenderingTypes.AMENITY_FINANCE){
if (zoom > 16){
if(subType == 1){
resId = R.drawable.h_atm;
} else if(subType == 2){
resId = R.drawable.h_bank;
}
}
} else if(type == MapRenderingTypes.AMENITY_TRANSPORTATION){
if (zoom >= 15){
if(subType == 1 || subType == 2){
resId = R.drawable.h_parking;
} else if(subType == 4){
resId = R.drawable.h_fuel;
} else if(subType == 18){
resId = R.drawable.h_bus_station;
}
}
}
private void drawPointBitmap(Canvas canvas, float x, float y, int type, int subType, int zoom) {
int resId = getPointBitmap(zoom, type, subType);
if(resId == 0){
// paintFill.setColor(clPoint);
// canvas.drawCircle(x, y, 6, paintFill);
} else {
drawBitmap(canvas, x, y, resId);
}
}
private void drawBitmap(Canvas canvas, float x, float y, int resId) {
Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), resId);
if (bmp != null) {
canvas.drawBitmap(bmp, x - bmp.getWidth() / 2, y - bmp.getHeight() / 2, paintText);
Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), resId);
if (bmp != null) {
canvas.drawBitmap(bmp, x - bmp.getWidth() / 2, y - bmp.getHeight() / 2, paintText);
}
}
}
private void drawHighway(MapRenderObject obj, Canvas canvas, double leftTileX, double topTileY, int zoom, float rotate) {
@ -360,9 +280,6 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
return;
}
float xText = 0;
float yText = 0;
Path path = null;
float pathRotate = 0;
float xLength = 0;
@ -422,74 +339,197 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
float yPrev = 0;
int middle = obj.getPointsLength() / 2;
for (int i = 0; i < obj.getPointsLength(); i++) {
float x = (float) ((MapUtils.getTileNumberX(zoom, obj.getPointLongitude(i)) - leftTileX) * 256f);
float y = (float) ((MapUtils.getTileNumberY(zoom, obj.getPointLatitude(i)) - topTileY) * 256f);
// xText += x;
// yText += y;
float lon = obj.getPointLongitude(i);
float lat = obj.getPointLatitude(i);
PointF p = calcPoint(leftTileX, topTileY, lat, lon, zoom, rotate);
if (path == null) {
path = new Path();
path.moveTo(x, y);
path.moveTo(p.x, p.y);
} else {
if (xPrev > 0) {
xLength += x - xPrev; // not abs
yLength += y - yPrev; // not abs
}
xLength += p.x - xPrev; // not abs
yLength += p.y - yPrev; // not abs
if(i == middle){
double rot = -Math.atan2(x - xPrev, y - yPrev) * 180 / Math.PI + 90;
double rot = - Math.atan2(p.x - xPrev, p.y - yPrev) * 180 / Math.PI;
if (rot < 0) {
rot += 360;
}
if (rot < 270 && rot > 90) {
if (rot < 180) {
rot += 180;
inverse = true;
}
pathRotate = (float) rot;
xText = (x + xPrev) / 2;
yText = (y + yPrev) / 2;
}
if (pathRotate == 0) {
}
path.lineTo(x, y);
path.lineTo(p.x, p.y);
}
xPrev = x;
yPrev = y;
xPrev = p.x;
yPrev = p.y;
}
if (path != null) {
// xText /= obj.getPointsLength();
// yText /= obj.getPointsLength();
canvas.drawPath(path, paint);
if (obj.getName() != null && carRoad) {
if (paintText.measureText(obj.getName()) < Math.max(Math.abs(xLength), Math.abs(yLength))) {
// paintText.setTextSize(paintText.getTextSize() + 2);
// int sv = canvas.save();
// canvas.rotate(pathRotate, xText, yText);
// canvas.drawText(obj.getName(), xText, yText, paintText);
// canvas.restoreToCount(sv);
if (inverse) {
path.rewind();
boolean st = true;
for (int i = obj.getPointsLength() - 1; i >= 0; i--) {
float x = (float) ((MapUtils.getTileNumberX(zoom, obj.getPointLongitude(i)) - leftTileX) * 256f);
float y = (float) ((MapUtils.getTileNumberY(zoom, obj.getPointLatitude(i)) - topTileY) * 256f);
float lon = obj.getPointLongitude(i);
float lat = obj.getPointLatitude(i);
PointF p = calcPoint(leftTileX, topTileY, lat, lon, zoom, rotate);
if (st) {
st = false;
path.moveTo(x, y);
path.moveTo(p.x, p.y);
} else {
path.lineTo(x, y);
path.lineTo(p.x, p.y);
}
}
}
canvas.drawTextOnPath(obj.getName(), path, 0, 0, paintText);
// paintText.setTextSize(paintText.getTextSize() - 2);
}
}
}
}
public static int getPointBitmap(int zoom, int type, int subType) {
int resId = 0;
if(type == MapRenderingTypes.HIGHWAY){
if (zoom > 16) {
if(subType == 38){
resId = R.drawable.h_traffic_light;
} else if(subType == 40){
resId = R.drawable.h_bus_stop;
}
}
} else if(type == MapRenderingTypes.SHOP){
if (zoom > 15) {
switch (subType) {
case 27:
case 65:
case 53:
resId = R.drawable.h_shop_supermarket;
break;
case 13:
resId = R.drawable.h_shop_clothes;
break;
case 31:
resId = R.drawable.h_shop_hairdresser;
break;
}
}
if (zoom > 16) {
switch (subType) {
case 48:
resId = R.drawable.h_shop_butcher;
break;
case 42:
resId = R.drawable.h_shop_bakery;
break;
case 20:
resId = R.drawable.h_shop_diy;
break;
case 16:
resId = R.drawable.h_shop_convenience;
break;
}
}
} else if(type == MapRenderingTypes.AMENITY_SUSTENANCE){
if (zoom > 15) {
switch (subType) {
case 1:
resId = R.drawable.h_restaurant;
break;
case 2:
resId = R.drawable.h_cafe;
break;
case 4:
resId = R.drawable.h_fast_food;
break;
case 5:
resId = R.drawable.h_pub;
break;
case 7:
case 6:
resId = R.drawable.h_bar;
break;
case 8:
resId = R.drawable.h_food_drinkingtap;
break;
}
}
} else if(type == MapRenderingTypes.AMENITY_EDUCATION){
if (zoom > 15){
if(subType == 2){
resId = R.drawable.h_school;
} else if(subType == 4){
resId = R.drawable.h_library;
}
}
} else if (type == MapRenderingTypes.AMENITY_TRANSPORTATION) {
if (subType == 1 || subType == 2) {
resId = R.drawable.h_parking;
} else if (subType == 4) {
resId = R.drawable.h_fuel;
} else if (subType == 18) {
resId = R.drawable.h_bus_station;
}
} else if (type == MapRenderingTypes.AMENITY_FINANCE) {
if (subType == 1) {
if (zoom > 16) {
resId = R.drawable.h_atm;
}
} else if (subType == 2) {
if (zoom > 15) {
resId = R.drawable.h_bank;
}
}
} else if (type == MapRenderingTypes.AMENITY_HEALTHCARE) {
if (subType == 1) {
if (zoom > 15) {
resId = R.drawable.h_pharmacy;
}
} else if (subType == 2) {
resId = R.drawable.h_hospital;
}
} else if(type == MapRenderingTypes.AMENITY_OTHER){
if (zoom > 16) {
switch (subType) {
case 10:
resId = R.drawable.h_police;
break;
case 18:
resId = R.drawable.h_toilets;
break;
case 15:
resId = R.drawable.h_recycling;
break;
case 7:
resId = R.drawable.h_embassy;
break;
case 8:
resId = R.drawable.h_grave_yard;
break;
case 17:
resId = R.drawable.h_telephone;
break;
case 11:
resId = R.drawable.h_postbox;
break;
case 12:
resId = R.drawable.h_postoffice;
break;
}
}
}
return resId;
}
}

View file

@ -50,8 +50,8 @@ public class RendererLayer implements OsmandMapLayer {
double leftLongitude = MapUtils.getLongitudeFromTile(view.getFloatZoom(), tileRect.left);
double bottomLatitude = MapUtils.getLatitudeFromTile(view.getFloatZoom(), tileRect.bottom);
double rightLongitude = MapUtils.getLongitudeFromTile(view.getFloatZoom(), tileRect.right);
resourceManager.updateRendererIfNeeded(topLatitude, leftLongitude, bottomLatitude, rightLongitude, view.getZoom());
RenderMapsRepositories renderer = resourceManager.getRenderer();
resourceManager.updateRendererIfNeeded(topLatitude, leftLongitude, bottomLatitude, rightLongitude, view.getZoom(), view.getRotate());
MapRenderRepositories renderer = resourceManager.getRenderer();
if (renderer != null && renderer.getBitmap() != null) {
RectF newLoc = renderer.getCachedWaysLoc();
double leftX1 = MapUtils.getTileNumberX(view.getFloatZoom(), newLoc.left);
@ -73,7 +73,6 @@ public class RendererLayer implements OsmandMapLayer {
public void setVisible(boolean visible) {
this.visible = visible;
view.setShowMapTiles(!visible);
view.refreshMap();
}

View file

@ -83,8 +83,6 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
// name of source map
private ITileSource map = null;
private boolean showMapTiles = true;
private IMapLocationListener locationListener;
private OnLongClickListener onLongClickListener;
@ -244,7 +242,8 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
public void setZoom(float zoom){
if (map == null || ((map.getMaximumZoomSupported() + OVERZOOM_IN) >= zoom && map.getMinimumZoomSupported() <= zoom)) {
if ((map == null && zoom < 22) ||
((map.getMaximumZoomSupported() + OVERZOOM_IN) >= zoom && map.getMinimumZoomSupported() <= zoom)) {
animatedDraggingThread.stopAnimating();
this.zoom = zoom;
refreshMap();
@ -254,7 +253,8 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
// for internal usage
@Override
public void zoomTo(float zoom, boolean notify) {
if (map == null || ((map.getMaximumZoomSupported() + OVERZOOM_IN) >= zoom && map.getMinimumZoomSupported() <= zoom)) {
if ((map == null && zoom < 22) ||
((map.getMaximumZoomSupported() + OVERZOOM_IN) >= zoom && map.getMinimumZoomSupported() <= zoom)) {
this.zoom = zoom;
refreshMap();
if(notify && locationListener != null){
@ -291,10 +291,10 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
public void setMap(ITileSource map) {
this.map = map;
if(map.getMaximumZoomSupported() + OVERZOOM_IN < this.zoom){
if(map !=null && map.getMaximumZoomSupported() + OVERZOOM_IN < this.zoom){
zoom = map.getMaximumZoomSupported() + OVERZOOM_IN;
}
if(map.getMinimumZoomSupported() > this.zoom){
if(map !=null && map.getMinimumZoomSupported() > this.zoom){
zoom = map.getMinimumZoomSupported();
}
refreshMap();
@ -449,10 +449,9 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
if (canvas != null) {
canvas.save();
boundsRect.set(0, 0, getWidth(), getHeight());
canvas.drawRect(boundsRect, paintWhiteFill);
canvas.rotate(rotate, w , h);
try {
if (showMapTiles) {
if (map != null) {
ResourceManager mgr = getApplication().getResourceManager();
boolean useInternet = OsmandSettings.isUsingInternetToDownloadTiles(getContext())
&& map.couldBeDownloadedFromInternet();
@ -507,7 +506,6 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
} else {
int xZoom = ((left + i) % div) * tileSize / div;
int yZoom = ((top + j) % div) * tileSize / div;
;
bitmapToZoom.set(xZoom, yZoom, xZoom + tileSize / div, yZoom + tileSize / div);
bitmapToDraw.set(x1, y1, x1 + ftileSize, y1 + ftileSize);
canvas.drawBitmap(bmp, bitmapToZoom, bitmapToDraw, paintBitmap);
@ -519,6 +517,19 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
}
}
}
} else {
calculateTileRectangle(boundsRect, w, h, tileX, tileY, tilesRect);
int left = (int) FloatMath.floor(tilesRect.left);
int top = (int) FloatMath.floor(tilesRect.top);
int width = (int) (FloatMath.ceil(tilesRect.right) - left);
int height = (int) (FloatMath.ceil(tilesRect.bottom) - top);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
float x1 = (i + left - tileX) * ftileSize + w;
float y1 = (j + top - tileY) * ftileSize + h;
drawEmptyTile(canvas, x1, y1, ftileSize);
}
}
}
drawOverMap(canvas);
} finally {
@ -586,22 +597,21 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
canvas.rotate(rotate, w , h);
try {
if (showMapTiles) {
Bitmap bmp = null;
if (map != null) {
ResourceManager mgr = getApplication().getResourceManager();
Bitmap bmp = mgr.getTileImageForMapSync(null, map, request.xTile, request.yTile, request.zoom, false);
float x = (request.xTile - tileX) * getTileSize() + w;
float y = (request.yTile - tileY) * getTileSize() + h;
float tileSize = getTileSize();
if (bmp == null) {
drawEmptyTile(canvas, x, y, tileSize);
} else {
bitmapToZoom.set(0, 0, getSourceTileSize(), getSourceTileSize());
bitmapToDraw.set(x, y, x + tileSize, y + tileSize);
canvas.drawBitmap(bmp, bitmapToZoom, bitmapToDraw, paintBitmap);
}
bmp = mgr.getTileImageForMapSync(null, map, request.xTile, request.yTile, request.zoom, false);
}
float x = (request.xTile - tileX) * getTileSize() + w;
float y = (request.yTile - tileY) * getTileSize() + h;
float tileSize = getTileSize();
if (bmp == null) {
drawEmptyTile(canvas, x, y, tileSize);
} else {
boundsRect.set(0, 0, getWidth(), getHeight());
canvas.drawRect(boundsRect, paintWhiteFill);
bitmapToZoom.set(0, 0, getSourceTileSize(), getSourceTileSize());
bitmapToDraw.set(x, y, x + tileSize, y + tileSize);
canvas.drawBitmap(bmp, bitmapToZoom, bitmapToDraw, paintBitmap);
}
drawOverMap(canvas);
} finally {
@ -640,7 +650,7 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
*/
public int getMapXForPoint(double longitude){
double tileX = MapUtils.getTileNumberX(zoom, longitude);
return (int) ((tileX - getXTile()) * getTileSize()+ getCenterPointX());
return (int) ((tileX - getXTile()) * getTileSize() + getCenterPointX());
}
public int getMapYForPoint(double latitude){
double tileY = MapUtils.getTileNumberY(zoom, latitude);
@ -758,13 +768,6 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
zoomPositionChanged(getFloatZoom());
}
public void setShowMapTiles(boolean visible){
this.showMapTiles = visible;
}
public boolean isShowMapTiles() {
return showMapTiles;
}
@Override