improve rotation

git-svn-id: https://osmand.googlecode.com/svn/trunk@502 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-09-17 06:24:18 +00:00
parent 428fab7854
commit 55cc4ab189
11 changed files with 410 additions and 161 deletions

View file

@ -8,7 +8,7 @@ package net.osmand;
public class ToDoConstants {
// TODO swing
// ! 12. Reinvent UI of swing app (remove Region object and clear other MapObject) use indexes to show results
// !!! 12. Reinvent UI of swing app (remove Region object and clear other MapObject) use indexes to show results
// TODO max 87
// ! 81. Add some objects to POI category (1) to add them into OSM 2) to help navigation)
@ -20,23 +20,31 @@ public class ToDoConstants {
// 89. Transport redesign UI (enable run from context menu, switch go to goal/not) !
// 90. Use Junidecode library on the client for fast english translation
// 91. Invent binary format (minimize disk space, maximize speed)
// 92. Replace poi index with standard map index and unify POI categories
// 93. Implement multytype vector objects (?) - building with fence, road & tram ... (binary format)
// TODO small improvements for release :
// 1. If select vector map, notice if there are no loaded maps.
// TODO Improvements:
// TODO Improvements :
// 1! VELCOM
// 2. rotate map gps without location
// +2. rotate map gps without location
// 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
//+ 15. Draw layers -> icons -> text. See intersects of double streets.
// +13! Support multiple database for map rendering
// 16. Internet access bits
// 17. Implement multipolygons to polygons
// TODO colors for road trunk and motorway
// 17. Implement multipolygons to polygons (!?) + coastline
// 18. Fix loading map data in rotated mode (check properly boundaries)
// 20. Add text to rendering (area, point, polyline)
// 21. Shield, ref.
// 22. Verify all POI has a point_type (in order to search them)
// 19. colors for road trunk and motorway
// 12. Fix : find proper location for streets ! centralize them (when create index)?
// TODO Check

View file

@ -418,17 +418,17 @@ public class DataIndexWriter {
}
public static void insertMapRenderObjectIndex(Map<PreparedStatement, Integer> statements,
PreparedStatement mapStat, PreparedStatement mapWayLocationsStat, Entity e, String name,
PreparedStatement mapStat, PreparedStatement mapWayLocationsStat, /*RTree mapTree, */Entity e, String name,
long id, int type, boolean inversePath, boolean writeAsPoint, int batchSize) throws SQLException {
assert IndexMapRenderObject.values().length == 4;
if(e instanceof Relation){
throw new IllegalArgumentException();
}
boolean init = false;
// int minX = Integer.MAX_VALUE;
// int maxX = 0;
// int minY = Integer.MAX_VALUE;
// int maxY = 0;
int minX = Integer.MAX_VALUE;
int maxX = 0;
int minY = Integer.MAX_VALUE;
int maxY = 0;
double minLat = 180;
double maxLat = -180;
double minLon = 360;
@ -458,10 +458,10 @@ public class DataIndexWriter {
maxLat = Math.max(maxLat, n.getLatitude());
minLon = Math.min(minLon, n.getLongitude());
maxLon = Math.max(maxLon, n.getLongitude());
// minX = Math.min(minX, x);
// maxX = Math.max(maxX, x);
// minY = Math.min(minY, y);
// maxY = Math.max(maxY, y);
minX = Math.min(minX, x);
maxX = Math.max(maxX, x);
minY = Math.min(minY, y);
maxY = Math.max(maxY, y);
init = true;
Algoritms.putIntToBytes(bytes, offset, y);
offset += 4;
@ -475,6 +475,17 @@ public class DataIndexWriter {
mapStat.setString(IndexMapRenderObject.NAME.ordinal() + 1, name);
mapStat.setBytes(IndexMapRenderObject.NODES.ordinal() + 1, bytes);
addBatch(statements, mapStat);
//
// try {
// mapTree.insert(new LeafElement(new Rect(minX, minY, maxX, maxY), id));
// } catch (RTreeInsertException e1) {
// // TODO
// e1.printStackTrace();
// } catch (IllegalValueException e1) {
// // TODO
// e1.printStackTrace();
// }
mapWayLocationsStat.setLong(1, id);
mapWayLocationsStat.setFloat(2, (float) minLon);

View file

@ -132,6 +132,8 @@ public class IndexCreator {
private PreparedStatement mapLocsStatLevel0;
private PreparedStatement mapLocsStatLevel1;
private PreparedStatement mapLocsStatLevel2;
// private RTree mapTree;
private Map<Long, List<Way>> lowLevelWaysSt = new LinkedHashMap<Long, List<Way>>();
private Map<Long, List<Way>> lowLevelWaysEnd = new LinkedHashMap<Long, List<Way>>();
@ -1192,7 +1194,7 @@ public class IndexCreator {
if (!skip) {
DataIndexWriter.insertMapRenderObjectIndex(pStatements, mapObjStat, mapLocations, e,
DataIndexWriter.insertMapRenderObjectIndex(pStatements, mapObjStat, mapLocations, /*mapTree, */e,
MapRenderingTypes.getEntityName(e), id, type, false, point, BATCH_SIZE);
}
}
@ -1313,6 +1315,12 @@ public class IndexCreator {
mapLocsStatLevel0 = DataIndexWriter.createStatementMapWaysLocationsInsert(mapConnection);
mapLocsStatLevel1 = DataIndexWriter.createStatementMapWaysLocationsInsertLevel2(mapConnection);
mapLocsStatLevel2 = DataIndexWriter.createStatementMapWaysLocationsInsertLevel3(mapConnection);
// try {
// mapTree = new RTree(mapFile.getAbsolutePath()+"_ind");
// } catch (RTreeException e) {
// // TODO
// e.printStackTrace();
// }
pStatements.put(mapObjStat, 0);
pStatements.put(mapLocsStatLevel0, 0);
pStatements.put(mapLocsStatLevel1, 0);
@ -1464,7 +1472,6 @@ public class IndexCreator {
}
// 5. writing low level maps
if(indexMap){
// TODO level !!!
for(Long l : lowLevelWaysSt.keySet()){
for(Way w : lowLevelWaysSt.get(l)){
int level = (int) (w.getId() & 3);
@ -1512,6 +1519,13 @@ public class IndexCreator {
if (mapConnection != null) {
mapConnection.commit();
mapConnection.close();
// try {
// mapTree.flush();
// } catch (RTreeException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
if (lastModifiedDate != null) {
mapFile.setLastModified(lastModifiedDate);
}
@ -1543,7 +1557,7 @@ public class IndexCreator {
st.close();
dbConn.close();
}
// TODO steps
public static void main(String[] args) throws IOException, SAXException, SQLException {
IndexCreator creator = new IndexCreator(new File("e:/Information/OSM maps/osmand/"));
@ -1551,13 +1565,28 @@ public class IndexCreator {
// creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/minsk.tmp.odb"));
// creator.generateIndexes(new File("e:/Information/OSM maps/belarus osm/minsk.osm"), new ConsoleProgressImplementation(3), null);
// creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/belarus_nodes.tmp.odb"));
// creator.generateIndexes(new File("e:/Information/OSM maps/belarus osm/belarus_2010_09_03.osm.bz2"), new ConsoleProgressImplementation(3), null);
creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/ams.tmp.odb"));
creator.generateIndexes(new File("e:/Information/OSM maps/osm_map/ams_part_map.osm"), new ConsoleProgressImplementation(3), null);
/*try {
// RTree rtree = new RTree("e:/Information/OSM maps/osmand/Belarus_2010_09_03.map.odb_ind");
// new Pack().packTree(rtree, "e:/Information/OSM maps/osmand/pack.ind");
RTree rtree = new RTree("e:/Information/OSM maps/osmand/pack.ind");
long rootIndex = rtree.getFileHdr().getRootIndex();
int s = calculateSize(rtree.getReadNode(rootIndex), rtree, "!-");
System.out.println(s);
} catch (RTreeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
// download base
/* MapTileDownloader instance = MapTileDownloader.getInstance();
@ -1583,5 +1612,27 @@ public class IndexCreator {
}*/
}
/*
public static int calculateSize(rtree.Node n, RTree r, String level){
Element[] e = n.getAllElements();
int exc = 0; //20 + (169 - n.getTotalElements()) * 24;
for(int i=0; i< n.getTotalElements(); i++){
if(e[i].getElementType() == rtree.Node.LEAF_NODE){
exc += 1;
} else {
// exc += 1;
long ptr = ((NonLeafElement) e[i]).getPtr();
try {
rtree.Node ns = r.getReadNode(ptr);
System.out.println(level + " " + ns.getTotalElements());
exc += calculateSize(ns, r, level +"-");
} catch (RTreeException e1) {
e1.printStackTrace();
}
}
}
return exc;
}
*/
}

View file

@ -47,6 +47,8 @@ public class MapRenderingTypes {
public final static int MASK_4 = (1 << 4) - 1;
public final static int MASK_10 = (1 << 10) - 1;
public final static String REF_CHAR = ((char)0x0019)+""; //$NON-NLS-1$
// TODO !!! add others facilities to all types
// TODO Internet access bits for point
@ -422,9 +424,16 @@ public class MapRenderingTypes {
return (attr & 3) == 1;
}
public static String getEntityName(Entity e){
public static String getEntityName(Entity e) {
if (e.getTag(OSMTagKey.REF) != null) {
String ref = e.getTag(OSMTagKey.REF);
if (ref.length() > 5 && ref.indexOf('_') != -1) {
ref = ref.substring(0, ref.indexOf('_'));
}
return REF_CHAR + ref;
}
String name = e.getTag(OSMTagKey.NAME);
if(name == null){
if (name == null) {
name = e.getTag(OSMTagKey.ADDR_HOUSE_NUMBER);
}
return name;

View file

@ -30,6 +30,7 @@ import android.content.Context;
import android.database.sqlite.SQLiteException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.RectF;
import android.os.Environment;
/**
@ -527,11 +528,13 @@ public class ResourceManager {
}
////////////////////////////////////////////// Working with map ////////////////////////////////////////////////
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, rotate));
}
public boolean updateRenderedMapNeeded(RectF tilesRect, int zoom, float rotate){
return renderer.updateMapIsNeeded(tilesRect, zoom, rotate);
}
public void updateRendererMap(RectF tileRect, RectF boundsTileRect, int zoom, float rotate){
asyncLoadingTiles.requestToLoadMap(
new MapLoadRequest(tileRect, boundsTileRect, zoom, rotate));
}
public MapRenderRepositories getRenderer() {
@ -677,20 +680,15 @@ public class ResourceManager {
}
private static class MapLoadRequest {
public final double topLatitude;
public final double bottomLatitude;
public final double leftLongitude;
public final double rightLongitude;
public final RectF tileRect;
public final RectF boundsTileRect;
public final int zoom;
public final float rotate;
public MapLoadRequest(double topLatitude, double leftLongitude,
double bottomLatitude, double rightLongitude, int zoom, float rotate) {
public MapLoadRequest(RectF tileRect, RectF boundsTileRect, int zoom, float rotate) {
super();
this.bottomLatitude = bottomLatitude;
this.leftLongitude = leftLongitude;
this.rightLongitude = rightLongitude;
this.topLatitude = topLatitude;
this.tileRect = tileRect;
this.boundsTileRect = boundsTileRect;
this.zoom = zoom;
this.rotate = rotate;
}
@ -735,7 +733,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, r.rotate);
renderer.loadMap(r.tileRect, r.boundsTileRect, r.zoom, r.rotate);
mapLoaded = true;
}
}

View file

@ -382,7 +382,6 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
@Override
protected void onStart() {
super.onStart();
}
@Override
@ -412,14 +411,14 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
private void registerUnregisterSensor(Location location){
boolean show = currentShowingAngle || currentMapRotation == OsmandSettings.ROTATE_MAP_COMPASS;
boolean show = (currentShowingAngle && location != null) || currentMapRotation == OsmandSettings.ROTATE_MAP_COMPASS;
// show point view only if gps enabled
if (sensorRegistered && (location == null || !show)) {
if (sensorRegistered && !show) {
Log.d(LogUtil.TAG, "Disable sensor"); //$NON-NLS-1$
((SensorManager) getSystemService(SENSOR_SERVICE)).unregisterListener(this);
sensorRegistered = false;
locationLayer.setHeading(null);
} else if (!sensorRegistered && (location != null && show)) {
} else if (!sensorRegistered && show) {
Log.d(LogUtil.TAG, "Enable sensor"); //$NON-NLS-1$
SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor s = sensorMgr.getDefaultSensor(Sensor.TYPE_ORIENTATION);
@ -671,6 +670,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
locationLayer.setAppMode(OsmandSettings.getApplicationMode(this));
routingHelper.setAppMode(OsmandSettings.getApplicationMode(this));
mapView.setMapPosition(OsmandSettings.getPositionOnMap(this));
registerUnregisterSensor(getLastKnownLocation());
updateLayers();
}
@ -736,6 +736,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
}
updateApplicationModeSettings();
favoritesLayer.reloadFavorites(this);
poiMapLayer.setFilter(OsmandSettings.getPoiFilterForMap(this, (OsmandApplication) getApplication()));

View file

@ -5,42 +5,51 @@ import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.osmand.IProgress;
import net.osmand.LogUtil;
import net.osmand.data.index.IndexConstants;
import net.osmand.osm.MapRenderObject;
import net.osmand.osm.MapUtils;
import org.apache.commons.logging.Log;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.RectF;
import android.util.FloatMath;
public class MapRenderRepositories {
private final static Log log = LogUtil.getLog(MapRenderRepositories.class);
private final Context context;
private Connection conn;
private PreparedStatement pStatement;
private PreparedStatement pStatement2;
private PreparedStatement pStatement3;
private Map<String, Connection> files = new LinkedHashMap<String, Connection>();
private Map<Connection, RectF> connections = new LinkedHashMap<Connection, RectF>();
private Map<Connection, PreparedStatement> pZoom0 = new LinkedHashMap<Connection, PreparedStatement>();
private Map<Connection, PreparedStatement> pZoom1 = new LinkedHashMap<Connection, PreparedStatement>();
private Map<Connection, PreparedStatement> pZoom2 = new LinkedHashMap<Connection, PreparedStatement>();
private OsmandRenderer renderer;
private double cTopLatitude;
private double cBottomLatitude;
private double cLeftLongitude;
private double cRightLongitude;
private double cTopY;
private double cBottomY;
private double cLeftX;
private double cRightX;
private int cZoom;
private float cRotate;
// cached objects in order to rotate without
private List<MapRenderObject> cObjects = new LinkedList<MapRenderObject>();
private RectF cachedWaysLoc = new RectF();
private float cachedRotate = 0;
private Bitmap bmp;
@ -54,17 +63,24 @@ public class MapRenderRepositories {
return context;
}
private RectF getBoundsForIndex(Statement stat, String tableName) throws SQLException{
ResultSet rs = stat.executeQuery("SELECT MIN(minLon), MAX(maxLat), MAX(maxLon), MIN(minLat) FROM " + IndexConstants.indexMapLocationsTable); //$NON-NLS-1$
RectF bounds = new RectF();
if(rs.next()){
bounds.set(rs.getFloat(1), rs.getFloat(2), rs.getFloat(3), rs.getFloat(4));
}
rs.close();
return bounds;
}
public boolean initializeNewResource(final IProgress progress, File file) {
long start = System.currentTimeMillis();
Connection conn = null;
if(files.containsKey(file.getAbsolutePath())){
closeConnection(files.get(file.getAbsolutePath()), file.getAbsolutePath());
}
try {
if (conn != null) {
// close previous db
conn.close();
conn = null;
pStatement = null;
pStatement2 = null;
pStatement3 = null;
}
try {
Class.forName("org.sqlite.JDBC"); //$NON-NLS-1$
} catch (Exception e) {
@ -72,9 +88,9 @@ public class MapRenderRepositories {
return false;
}
conn = DriverManager.getConnection("jdbc:sqlite:" + file.getAbsolutePath()); //$NON-NLS-1$
pStatement = conn.prepareStatement(loadMapQuery);
pStatement2 = conn.prepareStatement(loadMapQuery2);
pStatement3 = conn.prepareStatement(loadMapQuery3);
PreparedStatement pStatement = conn.prepareStatement(loadMapQuery);
PreparedStatement pStatement2 = conn.prepareStatement(loadMapQuery2);
PreparedStatement pStatement3 = conn.prepareStatement(loadMapQuery3);
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("PRAGMA user_version"); //$NON-NLS-1$
int v = rs.getInt(1);
@ -82,8 +98,16 @@ public class MapRenderRepositories {
if(v != IndexConstants.MAP_TABLE_VERSION){
return false;
}
RectF bounds = foundBounds(stat);
stat.close();
connections.put(conn, bounds);
files.put(file.getAbsolutePath(), conn);
pZoom0.put(conn, pStatement);
pZoom1.put(conn, pStatement2);
pZoom2.put(conn, pStatement3);
} catch (Exception e) {
log.error("No connection", e); //$NON-NLS-1$
if(conn != null){
@ -100,6 +124,49 @@ public class MapRenderRepositories {
}
return true;
}
private RectF foundBounds(Statement stat) throws SQLException {
String metaTable = "loc_meta_locations"; //$NON-NLS-1$
ResultSet rs = stat.executeQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='"+metaTable+"'"); //$NON-NLS-1$//$NON-NLS-2$
boolean dbExist = rs.next();
rs.close();
boolean found = false;
boolean write = true;
RectF bounds = new RectF();
if(dbExist){
rs = stat.executeQuery("SELECT MAX_LAT, MIN_LON, MIN_LAT, MAX_LON FROM " +metaTable); //$NON-NLS-1$
if(rs.next()){
bounds.set(rs.getFloat(2), rs.getFloat(1), rs.getFloat(4), rs.getFloat(3));
found = true;
} else {
found = false;
}
rs.close();
} else {
try {
stat.execute("CREATE TABLE " + metaTable + " (MAX_LAT DOUBLE, MIN_LON DOUBLE, MIN_LAT DOUBLE, MAX_LON DOUBLE)"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (RuntimeException e) {
// case when database is in readonly mode
write = false;
}
}
if (!found) {
bounds = getBoundsForIndex(stat, IndexConstants.indexMapLocationsTable);
if(bounds.left == bounds.right || bounds.bottom == bounds.top){
bounds = getBoundsForIndex(stat, IndexConstants.indexMapLocationsTable2);
if(bounds.left == bounds.right || bounds.bottom == bounds.top){
bounds = getBoundsForIndex(stat, IndexConstants.indexMapLocationsTable3);
}
}
if (write) {
stat.execute("INSERT INTO " + metaTable + " VALUES ("+Double.toString(bounds.top)+ ", "+Double.toString(bounds.left)+ ", " + //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Double.toString(bounds.bottom)+ ", "+Double.toString(bounds.right)+ ")"); //$NON-NLS-1$//$NON-NLS-2$
}
}
return bounds;
}
// if cache was changed different instance will be returned
@ -107,41 +174,46 @@ public class MapRenderRepositories {
return cachedWaysLoc;
}
public float getCachedRotate() {
return cachedRotate;
}
protected void closeConnection(Connection c, String file){
files.remove(c);
connections.remove(c);
pZoom0.remove(c);
pZoom1.remove(c);
pZoom2.remove(c);
try {
c.close();
} catch (java.sql.SQLException e) {
}
}
public void clearAllResources(){
clearCache();
if(conn != null){
try {
conn.close();
} catch (java.sql.SQLException e) {
}
conn = null;
pStatement = null;
pStatement2 = null;
pStatement3 = null;
for(String f : files.keySet()){
closeConnection(files.get(f), f);
}
}
/**
* @return true if no need to reevaluate map
*/
public boolean updateMapIsNotNeeded(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, float rotate){
if (conn == null) {
return true;
public boolean updateMapIsNeeded(RectF tileRect, int zoom, float rotate){
if (connections.isEmpty()) {
return false;
}
boolean inside = insideBox(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom);
boolean inside = insideBox(tileRect.top, tileRect.left, tileRect.bottom, tileRect.right, zoom);
if(rotate < 0){
rotate += 360;
}
return inside && Math.abs(rotate - cRotate) < 30;
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;
private boolean insideBox(double topY, double leftX, double bottomY, double rightX, int zoom) {
boolean inside = cZoom == zoom && cTopY <= topY && cLeftX <= leftX && cRightX >= rightX
&& cBottomY >= bottomY;
return inside;
}
@ -165,15 +237,19 @@ public class MapRenderRepositories {
" IN (SELECT id FROM "+IndexConstants.indexMapLocationsTable3 + //$NON-NLS-1$
" 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, float rotate) {
boolean inside = insideBox(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom);
public synchronized void loadMap(RectF tileRect, RectF boundsTileRect, int zoom, float rotate) {
// currently doesn't work properly (every rotate bounds will be outside)
boolean inside = insideBox(boundsTileRect.top, boundsTileRect.left, boundsTileRect.bottom, boundsTileRect.right, zoom);
cRotate = rotate < 0 ? rotate + 360 : rotate;
if (!inside) {
// that usable for portrait view
cBottomLatitude = bottomLatitude - (topLatitude - bottomLatitude) / 2;
cTopLatitude = topLatitude + (topLatitude - bottomLatitude) / 2;
cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude);
cRightLongitude = rightLongitude + (rightLongitude - leftLongitude);
cTopY = boundsTileRect.top;
cLeftX = boundsTileRect.left;
cRightX = boundsTileRect.right;
cBottomY = boundsTileRect.bottom;
double cBottomLatitude = MapUtils.getLatitudeFromTile(zoom, cBottomY);
double cTopLatitude = MapUtils.getLatitudeFromTile(zoom, cTopY);
double cLeftLongitude = MapUtils.getLongitudeFromTile(zoom, cLeftX);
double cRightLongitude = MapUtils.getLongitudeFromTile(zoom, cRightX);
cZoom = zoom;
log.info(String.format("BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", //$NON-NLS-1$
@ -181,72 +257,102 @@ public class MapRenderRepositories {
long now = System.currentTimeMillis();
PreparedStatement statement = null;
if(zoom >= 15){
statement = pStatement;
} else if(zoom >= 10){
statement = pStatement2;
} else if(zoom >= 6) {
statement = pStatement3;
}
if (statement == null || conn == null) {
if (connections.isEmpty()) {
cObjects = new ArrayList<MapRenderObject>();
// keep old results
return;
}
try {
statement.setDouble(1, cBottomLatitude);
statement.setDouble(2, cTopLatitude);
statement.setDouble(3, cLeftLongitude);
statement.setDouble(4, cRightLongitude);
ResultSet result = statement.executeQuery();
int count = 0;
List<MapRenderObject> local = new ArrayList<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);
Set<Long> ids = new LinkedHashSet<Long>();
for (Connection c : connections.keySet()) {
RectF r = connections.get(c);
boolean intersects = r.top >= cBottomLatitude && r.left <= cRightLongitude && r.right >= cLeftLongitude &&
r.bottom <= cTopLatitude;
if(!intersects){
continue;
}
PreparedStatement statement = null;
if (zoom >= 15) {
statement = pZoom0.get(c);
} else if (zoom >= 10) {
statement = pZoom1.get(c);
} else if (zoom >= 6) {
statement = pZoom2.get(c);
}
statement.setDouble(1, cBottomLatitude);
statement.setDouble(2, cTopLatitude);
statement.setDouble(3, cLeftLongitude);
statement.setDouble(4, cRightLongitude);
ResultSet result = statement.executeQuery();
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();
try {
while (result.next()) {
long id = result.getLong(1);
if(ids.contains(id)){
// do not add object twice
continue;
}
ids.add(id);
MapRenderObject obj = new MapRenderObject(id);
obj.setData(result.getBytes(2));
obj.setName(result.getString(3));
obj.setType(result.getInt(4));
count++;
local.add(obj);
}
} finally {
result.close();
}
}
cObjects = local;
log.info(String
.format("Search has been done in %s ms. %s results were found.", System.currentTimeMillis() - now, count)); //$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, cRotate);
RectF newLoc = new RectF((float)MapUtils.getLongitudeFromTile(zoom, tileRect.left), (float)MapUtils.getLatitudeFromTile(zoom, tileRect.top),
(float)MapUtils.getLongitudeFromTile(zoom, tileRect.right), (float)MapUtils.getLatitudeFromTile(zoom, tileRect.bottom));
int width = (int) calcDiffPixelX(cRotate, tileRect.right - tileRect.left, tileRect.bottom - tileRect.top);
int height = (int) calcDiffPixelY(cRotate, tileRect.right - tileRect.left, tileRect.bottom - tileRect.top);
Bitmap bmp = renderer.generateNewBitmap(width, height, tileRect.left, tileRect.top, cObjects, cZoom, cRotate);
Bitmap oldBmp = this.bmp;
this.bmp = bmp;
cachedWaysLoc = newLoc;
cachedRotate = cRotate;
if(oldBmp != null){
oldBmp.recycle();
}
}
public Bitmap getBitmap() {
return bmp;
}
public float calcDiffPixelX(float rotate, float dTileX, float dTileY){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.cos(rad) * dTileX - FloatMath.sin(rad) * dTileY) * OsmandRenderer.TILE_SIZE;
}
public float calcDiffPixelY(float rotate, float dTileX, float dTileY){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.sin(rad) * dTileX + FloatMath.cos(rad) * dTileY) * OsmandRenderer.TILE_SIZE;
}
public synchronized void clearCache() {
cObjects.clear();
cBottomLatitude = cLeftLongitude = cRightLongitude = cTopLatitude = cRotate = cZoom = 0;
cBottomY = cLeftX = cRightX = cTopY = cRotate = cZoom = 0;
if(bmp != null){
bmp.recycle();
bmp = null;

View file

@ -11,7 +11,6 @@ import java.util.Map;
import net.osmand.LogUtil;
import net.osmand.osm.MapRenderObject;
import net.osmand.osm.MapRenderingTypes;
import net.osmand.osm.MapUtils;
import org.apache.commons.logging.Log;
@ -41,9 +40,14 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
private TextPaint paintText;
private Paint paint;
private Paint paintShield;
private Paint paintFillEmpty;
private Paint paintIcon;
private float[] hsv = new float[3];
public static final int TILE_SIZE = 256;
/// Colors
private int clFillScreen = Color.rgb(241, 238, 232);
@ -66,6 +70,7 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
int textColor = Color.BLACK;
int textShadow = 0;
int textWrap = 0;
boolean shield = false;
}
private static class IconDrawInfo {
@ -78,14 +83,12 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
List<TextDrawInfo> textToDraw = new ArrayList<TextDrawInfo>();
List<IconDrawInfo> iconsToDraw = new ArrayList<IconDrawInfo>();
float leftX;
float rightX;
float bottomY;
float topY;
int width;
int height;
int zoom;
float rotate;
float cosRotate;
float sinRotate;
float tileDivisor;
// debug purpose
@ -94,6 +97,8 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
// use to calculate points
PointF tempPoint = new PointF();
float cosRotate;
float sinRotate;
// polyline props
@ -166,6 +171,10 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
paint = new Paint();
paint.setAntiAlias(true);
paintShield = new Paint();
paintShield.setAntiAlias(true);
paintFillEmpty = new Paint();
paintFillEmpty.setStyle(Style.FILL);
paintFillEmpty.setColor(clFillScreen);
@ -202,30 +211,30 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
public Bitmap generateNewBitmap(RectF objectLoc, List<MapRenderObject> objects, int zoom, float rotate) {
public Bitmap generateNewBitmap(int width, int height, float leftTileX, float topTileY,
List<MapRenderObject> objects, int zoom, float rotate) {
long now = System.currentTimeMillis();
Collections.sort(objects, this);
Bitmap bmp = null;
if (objects != null && !objects.isEmpty() && objectLoc.width() != 0f && objectLoc.height() != 0f) {
if (objects != null && !objects.isEmpty() && width > 0 && height > 0) {
// init rendering context
RenderingContext rc = new RenderingContext();
rc.leftX = (float) MapUtils.getTileNumberX(zoom, objectLoc.left);
rc.rightX = (float) MapUtils.getTileNumberX(zoom, objectLoc.right);
rc.topY = (float) MapUtils.getTileNumberY(zoom, objectLoc.top);
rc.bottomY = (float) MapUtils.getTileNumberY(zoom, objectLoc.bottom);
rc.leftX = leftTileX;
rc.topY = topTileY;
rc.zoom = zoom;
rc.rotate = rotate;
rc.width = width;
rc.height = height;
rc.tileDivisor = (int) (1 << (31 - zoom));
rc.cosRotate = FloatMath.cos((float) Math.toRadians(rotate));
rc.sinRotate = FloatMath.sin((float) Math.toRadians(rotate));
rc.tileDivisor = (int) (1 << (31 - zoom));
bmp = Bitmap.createBitmap(width, height, Config.RGB_565);
bmp = Bitmap.createBitmap((int) ((rc.rightX - rc.leftX) * 256), (int) ((rc.bottomY - rc.topY) * 256), Config.RGB_565);
Canvas cv = new Canvas(bmp);
cv.drawRect(0, 0, bmp.getWidth(), bmp.getHeight(), paintFillEmpty);
cv.rotate(-rotate);
for (MapRenderObject w : objects) {
draw(w, cv, rc);
for (MapRenderObject o : objects) {
draw(o, cv, rc);
}
for(IconDrawInfo icon : rc.iconsToDraw){
if(icon.resId != 0){
@ -256,7 +265,8 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
paintText.setColor(text.textColor);
RectF bounds = new RectF();
float mes = paintText.measureText(text.text);
if((text.pathRotate > 45 && text.pathRotate < 135) || (text.pathRotate > 225 && text.pathRotate < 315)){
if(text.drawOnPath == null ||
(text.pathRotate > 45 && text.pathRotate < 135) || (text.pathRotate > 225 && text.pathRotate < 315)){
bounds.set(text.centerX - mes / 2, text.centerY - 3 * text.textSize / 2,
text.centerX + mes / 2, text.centerY + 3 * text.textSize / 2);
} else {
@ -274,8 +284,25 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
}
}
boundsIntersect.add(bounds);
paintText.setFakeBoldText(false);
if(text.drawOnPath != null){
cv.drawTextOnPath(text.text, text.drawOnPath, 0, text.vOffset, paintText);
} else if(text.shield){
bounds.set(text.centerX - mes / 2 - 4, text.centerY - text.textSize,
text.centerX + mes / 2 + 4, text.centerY + text.textSize / 2);
paintShield.setStyle(Style.STROKE);
paintShield.setColor(Color.WHITE);
paintShield.setStrokeWidth(3);
cv.drawOval(bounds, paintShield);
paintShield.setStyle(Style.FILL);
Color.colorToHSV(paintText.getColor(), hsv);
hsv[2] *= 0.85;
paintShield.setColor(Color.HSVToColor(hsv));
cv.drawOval(bounds, paintShield);
paintText.setFakeBoldText(true);
paintText.setColor(Color.WHITE);
cv.drawText(text.text, text.centerX, text.centerY + 3, paintText);
} else {
cv.drawText(text.text, text.centerX, text.centerY, paintText);
}
@ -314,14 +341,18 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
rc.pointCount ++;
float tx = o.getPoint31XTile(ind) / rc.tileDivisor;
float ty = o.getPoint31YTile(ind) / rc.tileDivisor;
if(tx >= rc.leftX && tx <= rc.rightX && ty >= rc.topY && ty <= rc.bottomY){
rc.pointInsideCount++;
}
float dTileX = tx - rc.leftX;
float dTileY = ty - rc.topY;
float x = (rc.cosRotate * dTileX - rc.sinRotate * dTileY) * 256f ;
float y = (rc.sinRotate * dTileX + rc.cosRotate * dTileY) * 256f ;
float x = (rc.cosRotate * dTileX - rc.sinRotate * dTileY) * TILE_SIZE ;
float y = (rc.sinRotate * dTileX + rc.cosRotate * dTileY) * TILE_SIZE ;
rc.tempPoint.set(x, y);
// rc.tempPoint.set(dTileX * TILE_SIZE, dTileY * TILE_SIZE);
if(rc.tempPoint.x >= 0 && rc.tempPoint.x < rc.width &&
rc.tempPoint.y >= 0 && rc.tempPoint.y < rc.height){
rc.pointInsideCount++;
}
return rc.tempPoint;
}
@ -605,6 +636,17 @@ public class OsmandRenderer implements Comparator<MapRenderObject> {
text.textSize = w;
text.vOffset = rc.main.strokeWidth / 2 - 1;
rc.textToDraw.add(text);
if(text.text.startsWith(MapRenderingTypes.REF_CHAR)){
if(text.text.length() > 5){
text.text = text.text.substring(1, 5);
} else {
text.text = text.text.substring(1);
}
text.textColor = rc.second.strokeWidth != 0 ? rc.second.color : rc.main.color;
text.shield = true;
text.drawOnPath = null;
}
}
}
}

View file

@ -9,6 +9,7 @@ import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.FloatMath;
public class RendererLayer implements OsmandMapLayer {
@ -46,24 +47,34 @@ public class RendererLayer implements OsmandMapLayer {
pixRect.set(0, 0, view.getWidth(), view.getHeight());
view.calculateTileRectangle(pixRect, view.getCenterPointX(),
view.getCenterPointY(), view.getXTile(), view.getYTile(), tileRect);
double topLatitude = MapUtils.getLatitudeFromTile(view.getFloatZoom(), tileRect.top);
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(), view.getRotate());
if (view.getFloatZoom() == view.getZoom()
&& resourceManager.updateRenderedMapNeeded(tileRect, view.getZoom(), view.getRotate())) {
pixRect.set(-view.getWidth(), -view.getHeight()/2, 2*view.getWidth(), 3*view.getHeight()/2);
view.calculateTileRectangle(pixRect, view.getCenterPointX(),
view.getCenterPointY(), view.getXTile(), view.getYTile(), tileRect);
float xL = view.calcDiffTileX(pixRect.left - view.getCenterPointX(), pixRect.top - view.getCenterPointY()) + view.getXTile();
float xR = view.calcDiffTileX(pixRect.right - view.getCenterPointX(), pixRect.bottom - view.getCenterPointY()) + view.getXTile();
float yT = view.calcDiffTileY(pixRect.left - view.getCenterPointX(), pixRect.top - view.getCenterPointY())+ view.getYTile();
float yB = view.calcDiffTileY(pixRect.right - view.getCenterPointX(), pixRect.bottom - view.getCenterPointY()) + view.getYTile();
RectF verticesRect = new RectF(xL, yT, xR, yB);
resourceManager.updateRendererMap(verticesRect, tileRect, 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);
double rightX1 = MapUtils.getTileNumberX(view.getFloatZoom(), newLoc.right);
double topY1 = MapUtils.getTileNumberY(view.getFloatZoom(), newLoc.top);
double bottomY1 = MapUtils.getTileNumberY(view.getFloatZoom(), newLoc.bottom);
float x1 = (float) ((leftX1 - view.getXTile()) * view.getTileSize() + view.getCenterPointX());
float y1 = (float) ((topY1 - view.getYTile()) * view.getTileSize() + view.getCenterPointY());
float x2 = (float) ((rightX1 - view.getXTile()) * view.getTileSize() + view.getCenterPointX());
float y2 = (float) ((bottomY1 - view.getYTile()) * view.getTileSize() + view.getCenterPointY());
float rot = renderer.getCachedRotate();
float leftX1 = (float) MapUtils.getTileNumberX(view.getFloatZoom(), newLoc.left);
float rightX1 = (float) MapUtils.getTileNumberX(view.getFloatZoom(), newLoc.right);
float topY1 = (float) MapUtils.getTileNumberY(view.getFloatZoom(), newLoc.top);
float bottomY1 = (float) MapUtils.getTileNumberY(view.getFloatZoom(), newLoc.bottom);
float x1 = calcDiffPixelX(rot, leftX1 - view.getXTile(), topY1 - view.getYTile()) + view.getCenterPointX();
float y1 = calcDiffPixelY(rot, leftX1 - view.getXTile(), topY1 - view.getYTile()) + view.getCenterPointY();
float x2 = calcDiffPixelX(rot, rightX1 - view.getXTile(), bottomY1 - view.getYTile()) + view.getCenterPointX();
float y2 = calcDiffPixelY(rot, rightX1 - view.getXTile(), bottomY1 - view.getYTile()) + view.getCenterPointY();
canvas.rotate(-rot, view.getCenterPointX(), view.getCenterPointY());
destImage.set(x1, y1, x2, y2);
canvas.drawBitmap(renderer.getBitmap(), null, destImage, paintImg);
}
@ -71,6 +82,15 @@ public class RendererLayer implements OsmandMapLayer {
}
public float calcDiffPixelX(float rotate, float dTileX, float dTileY){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.cos(rad) * dTileX - FloatMath.sin(rad) * dTileY) * view.getTileSize();
}
public float calcDiffPixelY(float rotate, float dTileX, float dTileY){
float rad = (float) Math.toRadians(rotate);
return (FloatMath.sin(rad) * dTileX + FloatMath.cos(rad) * dTileY) * view.getTileSize() ;
}
public void setVisible(boolean visible) {
this.visible = visible;
view.refreshMap();

View file

@ -646,6 +646,7 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
return (FloatMath.cos(rad) * dTileX - FloatMath.sin(rad) * dTileY) * getTileSize() ;
}
/**
* These methods do not consider rotating
*/

View file

@ -31,6 +31,7 @@ import alice.tuprolog.Var;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.Environment;
import android.view.WindowManager;
public class CommandPlayer {
@ -200,6 +201,7 @@ public class CommandPlayer {
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
mediaPlayer = new MediaPlayer();
int sleep = 60;
boolean delay = true;