diff --git a/DataExtractionOSM/src/com/osmand/data/index/DownloaderIndexFromGoogleCode.java b/DataExtractionOSM/src/com/osmand/data/index/DownloaderIndexFromGoogleCode.java index 19d13641dd..d9372d68f4 100644 --- a/DataExtractionOSM/src/com/osmand/data/index/DownloaderIndexFromGoogleCode.java +++ b/DataExtractionOSM/src/com/osmand/data/index/DownloaderIndexFromGoogleCode.java @@ -23,8 +23,9 @@ public class DownloaderIndexFromGoogleCode { */ public static void main(String[] args) throws URISyntaxException, IOException { Map indexFiles = DownloaderIndexFromGoogleCode.getIndexFiles(new String[] { IndexConstants.ADDRESS_INDEX_EXT, - IndexConstants.POI_INDEX_EXT }, new String[] { - IndexConstants.ADDRESS_TABLE_VERSION + "", IndexConstants.POI_TABLE_VERSION + "" }); //$NON-NLS-1$//$NON-NLS-2$ + IndexConstants.POI_INDEX_EXT, IndexConstants.TRANSPORT_INDEX_EXT }, new String[] { + IndexConstants.ADDRESS_TABLE_VERSION + "", IndexConstants.POI_TABLE_VERSION + "", //$NON-NLS-1$//$NON-NLS-2$ + IndexConstants.TRANSPORT_TABLE_VERSION + "" }); //$NON-NLS-1$ System.out.println(indexFiles); } diff --git a/DataExtractionOSM/src/com/osmand/data/index/IndexConstants.java b/DataExtractionOSM/src/com/osmand/data/index/IndexConstants.java index 768a7a3c00..a24cb32cd0 100644 --- a/DataExtractionOSM/src/com/osmand/data/index/IndexConstants.java +++ b/DataExtractionOSM/src/com/osmand/data/index/IndexConstants.java @@ -290,7 +290,7 @@ public class IndexConstants { // Transport Index public enum IndexTransportStop implements IndexColumn { - ID("long"), LATITUDE("double", true), LONGITUDE("double", true), NAME, NAME_EN; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + ID("long"), LATITUDE("double", true), LONGITUDE("double", true), NAME, NAME_EN; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ boolean index = false; String type = null; @@ -327,7 +327,7 @@ public class IndexConstants { public enum IndexTransportRouteStop implements IndexColumn { - STOP("long"), ROUTE("long", true), DIRECTION("boolean"); //$NON-NLS-1$ //$NON-NLS-2$ + STOP("long"), ROUTE("long", true), DIRECTION("boolean"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ boolean index = false; String type = null; diff --git a/DataExtractionOSM/src/messages.properties b/DataExtractionOSM/src/messages.properties index 2b9bffb364..19d1388e40 100644 --- a/DataExtractionOSM/src/messages.properties +++ b/DataExtractionOSM/src/messages.properties @@ -29,6 +29,8 @@ indexing_address = Indexing address indexing_poi = Indexing POI +indexing_transport = Indexing transport + km = km km_h = km/h diff --git a/DataExtractionOSM/src/messages_ru.properties b/DataExtractionOSM/src/messages_ru.properties index 5d5797cff8..c807a1a928 100644 --- a/DataExtractionOSM/src/messages_ru.properties +++ b/DataExtractionOSM/src/messages_ru.properties @@ -29,6 +29,8 @@ indexing_address = \u0418\u043D\u0434\u0435\u043A\u0441\u0438\u0440\u0443\u0435\ indexing_poi = \u0418\u043D\u0434\u0435\u043A\u0441\u0438\u0440\u0443\u044E\u0442\u0441\u044F POI +indexing_transport = \u0418\u043D\u0434\u0435\u043A\u0441\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u0442\u0440\u0430\u043D\u0441\u043F\u043E\u0440\u0442 + km = \u043A\u043C km_h = \u043A\u043C/\u0447 diff --git a/OsmAnd/src/com/osmand/AmenityIndexRepository.java b/OsmAnd/src/com/osmand/AmenityIndexRepository.java index cd4fb8b95a..2fecb4ff54 100644 --- a/OsmAnd/src/com/osmand/AmenityIndexRepository.java +++ b/OsmAnd/src/com/osmand/AmenityIndexRepository.java @@ -11,7 +11,6 @@ import org.apache.commons.logging.Log; import org.xml.sax.SAXException; import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteStatement; import com.osmand.data.Amenity; @@ -24,30 +23,15 @@ import com.osmand.osm.Node; import com.osmand.osm.io.IOsmStorageFilter; import com.osmand.osm.io.OsmBaseStorage; -public class AmenityIndexRepository { +public class AmenityIndexRepository extends BaseLocationIndexRepository { private static final Log log = LogUtil.getLog(AmenityIndexRepository.class); public final static int LIMIT_AMENITIES = 500; - - private SQLiteDatabase db; - private double dataTopLatitude; - private double dataBottomLatitude; - private double dataLeftLongitude; - private double dataRightLongitude; - - private String name; - + // cache amenities - private List cachedAmenities = new ArrayList(); - private double cTopLatitude; - private double cBottomLatitude; - private double cLeftLongitude; - private double cRightLongitude; - private int cZoom; private String cFilterId; - private final String[] columns = IndexConstants.generateColumnNames(IndexPoiTable.values()); public List searchAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int limit, PoiFilter filter, List amenities){ long now = System.currentTimeMillis(); @@ -122,13 +106,8 @@ public class AmenityIndexRepository { public synchronized void clearCache(){ - cachedAmenities.clear(); - cTopLatitude = 0; - cBottomLatitude = 0; - cRightLongitude = 0; - cLeftLongitude = 0; + super.clearCache(); cFilterId = null; - cZoom = 0; } public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, int limit, PoiFilter filter, List toFill){ @@ -142,8 +121,8 @@ public class AmenityIndexRepository { ArrayList tempList = new ArrayList(); searchAmenities(cTopLatitude, cLeftLongitude, cBottomLatitude, cRightLongitude, limit, filter, tempList); synchronized (this) { - cachedAmenities.clear(); - cachedAmenities.addAll(tempList); + cachedObjects.clear(); + cachedObjects.addAll(tempList); } checkCachedAmenities(topLatitude, leftLongitude, bottomLatitude, rightLongitude, cZoom, filter.getFilterId(), toFill); @@ -157,7 +136,7 @@ public class AmenityIndexRepository { && cBottomLatitude <= bottomLatitude && zoom == cZoom; boolean noNeedToSearch = inside && Algoritms.objectEquals(filterId, cFilterId); if((inside || fillFound) && toFill != null && Algoritms.objectEquals(filterId, cFilterId)){ - for(Amenity a : cachedAmenities){ + for(Amenity a : cachedObjects){ LatLon location = a.getLocation(); if (location.getLatitude() <= topLatitude && location.getLongitude() >= leftLongitude && location.getLongitude() <= rightLongitude && location.getLatitude() >= bottomLatitude) { @@ -172,53 +151,10 @@ public class AmenityIndexRepository { } public boolean initialize(final IProgress progress, File file) { - long start = System.currentTimeMillis(); - if(db != null){ - // close previous db - db.close(); - } - db = SQLiteDatabase.openOrCreateDatabase(file, null); - name = file.getName().substring(0, file.getName().indexOf('.')); - if(db.getVersion() != IndexConstants.POI_TABLE_VERSION){ - db.close(); - db = null; - return false; - } - - Cursor query = db.query(IndexPoiTable.getTable(), new String[]{"MAX(latitude)", "MAX(longitude)", "MIN(latitude)", "MIN(longitude)"}, null, null,null, null, null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - if(query.moveToFirst()){ - dataTopLatitude = query.getDouble(0); - dataRightLongitude = query.getDouble(1); - dataBottomLatitude = query.getDouble(2); - dataLeftLongitude = query.getDouble(3); - } - query.close(); - if (log.isDebugEnabled()) { - log.debug("Initializing db " + file.getAbsolutePath() + " " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - return true; + return super.initialize(progress, file, IndexConstants.POI_TABLE_VERSION, IndexPoiTable.getTable()); } - public synchronized void close(){ - if(db != null){ - db.close(); - dataRightLongitude = dataLeftLongitude = dataBottomLatitude= dataTopLatitude = 0; - cachedAmenities.clear(); - cTopLatitude = cBottomLatitude = cLeftLongitude = cRightLongitude = 0; - } - } - public String getName() { - return name; - } - - private void bindString(SQLiteStatement s, int i, String v){ - if(v == null){ - s.bindNull(i); - } else { - s.bindString(i, v); - } - } public boolean updateAmenities(List amenities, double leftLon, double topLat, double rightLon, double bottomLat){ String latCol = IndexPoiTable.LATITUDE.name(); @@ -242,24 +178,6 @@ public class AmenityIndexRepository { stat.close(); return true; } - - public boolean checkContains(double latitude, double longitude){ - if(latitude < dataTopLatitude && latitude > dataBottomLatitude && longitude > dataLeftLongitude && longitude < dataRightLongitude){ - return true; - } - return false; - } - - public boolean checkContains(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude){ - if(rightLongitude < dataLeftLongitude || leftLongitude > dataRightLongitude){ - return false; - } - if(topLatitude < dataBottomLatitude || bottomLatitude > dataTopLatitude){ - return false; - } - return true; - } - private final static String SITE_API = "http://api.openstreetmap.org/"; //$NON-NLS-1$ diff --git a/OsmAnd/src/com/osmand/BaseLocationIndexRepository.java b/OsmAnd/src/com/osmand/BaseLocationIndexRepository.java new file mode 100644 index 0000000000..07131b5cc5 --- /dev/null +++ b/OsmAnd/src/com/osmand/BaseLocationIndexRepository.java @@ -0,0 +1,133 @@ +package com.osmand; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; + +import com.osmand.data.MapObject; +import com.osmand.osm.LatLon; + +public class BaseLocationIndexRepository { + private static final Log log = LogUtil.getLog(BaseLocationIndexRepository.class); + protected SQLiteDatabase db; + protected double dataTopLatitude; + protected double dataBottomLatitude; + protected double dataLeftLongitude; + protected double dataRightLongitude; + + protected String name; + + protected List cachedObjects = new ArrayList(); + protected double cTopLatitude; + protected double cBottomLatitude; + protected double cLeftLongitude; + protected double cRightLongitude; + protected int cZoom; + + + + public synchronized void clearCache(){ + cachedObjects.clear(); + cTopLatitude = 0; + cBottomLatitude = 0; + cRightLongitude = 0; + cLeftLongitude = 0; + cZoom = 0; + } + + public boolean initialize(final IProgress progress, File file, int version, String tableLocation) { + long start = System.currentTimeMillis(); + if(db != null){ + // close previous db + db.close(); + } + db = SQLiteDatabase.openOrCreateDatabase(file, null); + name = file.getName().substring(0, file.getName().indexOf('.')); + if(db.getVersion() != version){ + db.close(); + db = null; + return false; + } + + Cursor query = db.query(tableLocation, new String[]{"MAX(latitude)", "MAX(longitude)", "MIN(latitude)", "MIN(longitude)"}, null, null,null, null, null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + if(query.moveToFirst()){ + dataTopLatitude = query.getDouble(0); + dataRightLongitude = query.getDouble(1); + dataBottomLatitude = query.getDouble(2); + dataLeftLongitude = query.getDouble(3); + } + query.close(); + if (log.isDebugEnabled()) { + log.debug("Initializing db " + file.getAbsolutePath() + " " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + return true; + } + + public synchronized void close() { + if (db != null) { + db.close(); + dataRightLongitude = dataLeftLongitude = dataBottomLatitude = dataTopLatitude = 0; + clearCache(); + db = null; + } + } + + public String getName() { + return name; + } + + protected void bindString(SQLiteStatement s, int i, String v){ + if(v == null){ + s.bindNull(i); + } else { + s.bindString(i, v); + } + } + + + public boolean checkCachedObjects(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, List toFill){ + return checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, toFill, false); + } + + public synchronized boolean checkCachedObjects(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, List toFill, boolean fillFound){ + if (db == null) { + return true; + } + boolean inside = cTopLatitude >= topLatitude && cLeftLongitude <= leftLongitude && cRightLongitude >= rightLongitude + && cBottomLatitude <= bottomLatitude && cZoom == zoom; + boolean noNeedToSearch = inside; + if((inside || fillFound) && toFill != null){ + for(T a : cachedObjects){ + LatLon location = a.getLocation(); + if (location.getLatitude() <= topLatitude && location.getLongitude() >= leftLongitude && location.getLongitude() <= rightLongitude + && location.getLatitude() >= bottomLatitude) { + toFill.add(a); + } + } + } + return noNeedToSearch; + } + + public boolean checkContains(double latitude, double longitude){ + if(latitude < dataTopLatitude && latitude > dataBottomLatitude && longitude > dataLeftLongitude && longitude < dataRightLongitude){ + return true; + } + return false; + } + + public boolean checkContains(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude){ + if(rightLongitude < dataLeftLongitude || leftLongitude > dataRightLongitude){ + return false; + } + if(topLatitude < dataBottomLatitude || bottomLatitude > dataTopLatitude){ + return false; + } + return true; + } +} diff --git a/OsmAnd/src/com/osmand/ResourceManager.java b/OsmAnd/src/com/osmand/ResourceManager.java index 69b093be96..0171a29b4a 100644 --- a/OsmAnd/src/com/osmand/ResourceManager.java +++ b/OsmAnd/src/com/osmand/ResourceManager.java @@ -18,6 +18,7 @@ import android.graphics.BitmapFactory; import android.os.Environment; import com.osmand.data.Amenity; +import com.osmand.data.TransportStop; import com.osmand.data.index.IndexConstants; import com.osmand.data.preparation.MapTileDownloader; import com.osmand.data.preparation.MapTileDownloader.DownloadRequest; @@ -36,9 +37,13 @@ import com.osmand.views.POIMapLayer; */ public class ResourceManager { - public static final String POI_PATH = "osmand/" + IndexConstants.POI_INDEX_DIR; //$NON-NLS-1$ - public static final String ADDRESS_PATH = "osmand/" + IndexConstants.ADDRESS_INDEX_DIR; //$NON-NLS-1$ - public static final String TILES_PATH = "osmand/tiles/"; //$NON-NLS-1$ + public static final String APP_DIR = "osmand/"; //$NON-NLS-1$ + public static final String POI_PATH = APP_DIR + IndexConstants.POI_INDEX_DIR; + public static final String ADDRESS_PATH = APP_DIR + IndexConstants.ADDRESS_INDEX_DIR; + 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 int LIMIT_TRANSPORT = 200; private static final Log log = LogUtil.getLog(ResourceManager.class); @@ -66,6 +71,8 @@ public class ResourceManager { protected Map amenityRepositories = new LinkedHashMap(); + protected Map transportRepositories = new LinkedHashMap(); + public AsyncLoadingThread asyncLoadingTiles = new AsyncLoadingThread(); @@ -230,6 +237,7 @@ public class ResourceManager { List warnings = new ArrayList(); warnings.addAll(indexingPoi(progress)); warnings.addAll(indexingAddresses(progress)); + warnings.addAll(indexingTransport(progress)); return warnings; } @@ -286,8 +294,34 @@ public class ResourceManager { } } - // //////////////////////////////////////////// Working with amenities //////////////////////////////////////////////// - public List searchRepositories(double latitude, double longitude) { + + public List indexingTransport(final IProgress progress){ + File file = new File(Environment.getExternalStorageDirectory(), TRANSPORT_PATH); + List warnings = new ArrayList(); + closeTransport(); + if (file.exists() && file.canRead()) { + for (File f : file.listFiles()) { + indexingTransport(progress, warnings, f); + } + } + return warnings; + } + + public void indexingTransport(final IProgress progress, List warnings, File f) { + if (f.getName().endsWith(IndexConstants.TRANSPORT_INDEX_EXT)) { + TransportIndexRepository repository = new TransportIndexRepository(); + progress.startTask(Messages.getMessage("indexing_transport") + f.getName(), -1); //$NON-NLS-1$ + boolean initialized = repository.initialize(progress, f); + if (initialized) { + transportRepositories.put(repository.getName(), repository); + } else { + warnings.add(MessageFormat.format(Messages.getMessage("version_index_is_not_supported"), f.getName())); //$NON-NLS-1$ + } + } + } + + ////////////////////////////////////////////// Working with amenities //////////////////////////////////////////////// + public List searchAmenityRepositories(double latitude, double longitude) { List repos = new ArrayList(); for (AmenityIndexRepository index : amenityRepositories.values()) { if (index.checkContains(latitude,longitude)) { @@ -338,6 +372,47 @@ public class ResourceManager { return addressMap.values(); } + ////////////////////////////////////////////// Working with transport //////////////////////////////////////////////// + public List searchTransportRepositories(double latitude, double longitude) { + List repos = new ArrayList(); + for (TransportIndexRepository index : transportRepositories.values()) { + if (index.checkContains(latitude,longitude)) { + repos.add(index); + } + } + return repos; + } + public List searchTransportStops(double latitude, double longitude, int zoom, int limit) { + double tileNumberX = MapUtils.getTileNumberX(zoom, longitude); + double tileNumberY = MapUtils.getTileNumberY(zoom, latitude); + double topLatitude = MapUtils.getLatitudeFromTile(zoom, tileNumberY - 0.5); + double bottomLatitude = MapUtils.getLatitudeFromTile(zoom, tileNumberY + 0.5); + double leftLongitude = MapUtils.getLongitudeFromTile(zoom, tileNumberX - 0.5); + double rightLongitude = MapUtils.getLongitudeFromTile(zoom, tileNumberX + 0.5); + List stops = new ArrayList(); + for (TransportIndexRepository index : transportRepositories.values()) { + if (index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)) { + if (!index.checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, stops)) { + index.searchTransportStops(topLatitude, leftLongitude, bottomLatitude, rightLongitude, limit, stops); + } + } + } + + return stops; + } + + public void searchTransportAsync(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, List toFill){ + for(TransportIndexRepository index : transportRepositories.values()){ + if(index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)){ + if(!index.checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, toFill, true)){ + asyncLoadingTiles.requestToLoadTransport( + new TransportLoadRequest(index, topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom)); + } + } + } + } + + ////////////////////////////////////////////// Closing methods //////////////////////////////////////////////// public void closeAmenities(){ @@ -353,11 +428,19 @@ public class ResourceManager { } addressMap.clear(); } + + public void closeTransport(){ + for(TransportIndexRepository r : transportRepositories.values()){ + r.close(); + } + transportRepositories.clear(); + } public synchronized void close(){ imagesOnFS.clear(); closeAmenities(); closeAddresses(); + closeTransport(); } /// On low memory method /// @@ -423,11 +506,27 @@ public class ResourceManager { this.zoom = zoom; this.filter = filter; } - - - } + private static class TransportLoadRequest { + public final TransportIndexRepository repository; + public final double topLatitude; + public final double bottomLatitude; + public final double leftLongitude; + public final double rightLongitude; + public final int zoom; + + public TransportLoadRequest(TransportIndexRepository repository, double topLatitude, double leftLongitude, + double bottomLatitude, double rightLongitude, int zoom) { + super(); + this.bottomLatitude = bottomLatitude; + this.leftLongitude = leftLongitude; + this.repository = repository; + this.rightLongitude = rightLongitude; + this.topLatitude = topLatitude; + this.zoom = zoom; + } + } public class AsyncLoadingThread extends Thread { Stack requests = new Stack(); @@ -442,6 +541,7 @@ public class ResourceManager { try { boolean update = false; boolean amenityLoaded = false; + boolean transportLoaded = false; while(!requests.isEmpty()){ Object req = requests.pop(); if (req instanceof TileLoadDownloadRequest) { @@ -456,9 +556,16 @@ public class ResourceManager { r.bottomLatitude, r.rightLongitude, r.zoom, POIMapLayer.LIMIT_POI, r.filter, null); amenityLoaded = true; } + } else if(req instanceof TransportLoadRequest){ + if(!transportLoaded){ + TransportLoadRequest r = (TransportLoadRequest) req; + r.repository.evaluateCachedTransportStops(r.topLatitude, r.leftLongitude, + r.bottomLatitude, r.rightLongitude, r.zoom, LIMIT_TRANSPORT, null); + transportLoaded = true; + } } } - if(update || amenityLoaded){ + if(update || amenityLoaded || transportLoaded){ // use downloader callback for(IMapDownloaderCallback c : downloader.getDownloaderCallbacks()){ c.tileDownloaded(null); @@ -479,5 +586,9 @@ public class ResourceManager { public void requestToLoadAmenities(AmenityLoadRequest req){ requests.push(req); } + + public void requestToLoadTransport(TransportLoadRequest req){ + requests.push(req); + } }; } diff --git a/OsmAnd/src/com/osmand/TransportIndexRepository.java b/OsmAnd/src/com/osmand/TransportIndexRepository.java new file mode 100644 index 0000000000..7f0239f4f7 --- /dev/null +++ b/OsmAnd/src/com/osmand/TransportIndexRepository.java @@ -0,0 +1,117 @@ +package com.osmand; + +import java.io.File; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; + +import android.database.Cursor; + +import com.osmand.data.TransportStop; +import com.osmand.data.index.IndexConstants; +import com.osmand.data.index.IndexConstants.IndexTransportRoute; +import com.osmand.data.index.IndexConstants.IndexTransportRouteStop; +import com.osmand.data.index.IndexConstants.IndexTransportStop; + +public class TransportIndexRepository extends BaseLocationIndexRepository { + private static final Log log = LogUtil.getLog(TransportIndexRepository.class); + + + public boolean initialize(final IProgress progress, File file) { + return super.initialize(progress, file, IndexConstants.TRANSPORT_TABLE_VERSION, IndexTransportStop.getTable()); + } + + + private final String[] columns = IndexConstants.generateColumnNames(IndexTransportStop.values()); + public List searchTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int limit, List stops){ + long now = System.currentTimeMillis(); + String squery = "? < latitude AND latitude < ? AND ? < longitude AND longitude < ?"; //$NON-NLS-1$ + + if(limit != -1){ + squery += " ORDER BY RANDOM() LIMIT " +limit; //$NON-NLS-1$ + } + Cursor query = db.query(IndexTransportStop.getTable(), columns, squery, + new String[]{Double.toString(bottomLatitude), + Double.toString(topLatitude), Double.toString(leftLongitude), Double.toString(rightLongitude)}, null, null, null); + if(query.moveToFirst()){ + do { + TransportStop st = new TransportStop(); + st.setId(query.getLong(IndexTransportStop.ID.ordinal())); + st.setLocation(query.getDouble(IndexTransportStop.LATITUDE.ordinal()), + query.getDouble(IndexTransportStop.LONGITUDE.ordinal())); + st.setName(query.getString(IndexTransportStop.NAME.ordinal() )); + st.setEnName(query.getString(IndexTransportStop.NAME_EN.ordinal())); + stops.add(st); + if(limit != -1 && stops.size() >= limit){ + break; + } + } while(query.moveToNext()); + } + query.close(); + + if (log.isDebugEnabled()) { + log.debug(String.format("Search for %s done in %s ms found %s.", //$NON-NLS-1$ + topLatitude + " " + leftLongitude, System.currentTimeMillis() - now, stops.size())); //$NON-NLS-1$ + } + return stops; + } + + + + private static String cacheSQLRouteDescriptions = null; + /** + * + * @param stop + * @param format {0} - ref, {1} - type, {2} - name, {3} - name_en + * @return + */ + public List getRouteDescriptionsForStop(TransportStop stop, String format) { + long now = System.currentTimeMillis(); + List res = new ArrayList(); + MessageFormat f = new MessageFormat(format); + + if (cacheSQLRouteDescriptions == null) { + StringBuilder sql = new StringBuilder(200); + sql.append("SELECT ").append(IndexTransportRoute.REF).append(",").append(IndexTransportRoute.TYPE) //$NON-NLS-1$//$NON-NLS-2$ + .append(",").append(IndexTransportRoute.NAME).append(",").append(IndexTransportRoute.NAME_EN); //$NON-NLS-1$ //$NON-NLS-2$ + sql.append(" FROM ").append(IndexTransportRoute.getTable()).append(" JOIN ").append(IndexTransportRouteStop.getTable()); //$NON-NLS-1$ //$NON-NLS-2$ + sql.append(" ON ").append(IndexTransportRoute.getTable()).append(".").append(IndexTransportRoute.ID).append(" = "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + sql.append(IndexTransportRouteStop.getTable()).append(".").append(IndexTransportRouteStop.ROUTE); //$NON-NLS-1$ + sql.append(" WHERE ").append(IndexTransportRouteStop.STOP).append(" = ?"); //$NON-NLS-1$ //$NON-NLS-2$ + cacheSQLRouteDescriptions = sql.toString(); + } + Cursor query = db.rawQuery(cacheSQLRouteDescriptions, new String[] { stop.getId() + "" }); //$NON-NLS-1$ + if (query.moveToFirst()) { + do { + res.add(f.format(new String[] { query.getString(0), query.getString(1), query.getString(2), query.getString(3) })); + } while (query.moveToNext()); + } + query.close(); + + if (log.isDebugEnabled()) { + log.debug(String.format("Search for stop %s done in %s ms found %s.", //$NON-NLS-1$ + stop.getId() + "", System.currentTimeMillis() - now, res.size())); //$NON-NLS-1$ + } + return res; + } + + + public void evaluateCachedTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, int limit, List toFill){ + cTopLatitude = topLatitude + (topLatitude -bottomLatitude); + cBottomLatitude = bottomLatitude - (topLatitude -bottomLatitude); + cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude); + cRightLongitude = rightLongitude + (rightLongitude - leftLongitude); + cZoom = zoom; + // first of all put all entities in temp list in order to not freeze other read threads + ArrayList tempList = new ArrayList(); + searchTransportStops(cTopLatitude, cLeftLongitude, cBottomLatitude, cRightLongitude, limit, tempList); + synchronized (this) { + cachedObjects.clear(); + cachedObjects.addAll(tempList); + } + + checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, cZoom, toFill); + } +} diff --git a/OsmAnd/src/com/osmand/activities/DownloadIndexActivity.java b/OsmAnd/src/com/osmand/activities/DownloadIndexActivity.java index ada8febf0c..30fd6f3ce7 100644 --- a/OsmAnd/src/com/osmand/activities/DownloadIndexActivity.java +++ b/OsmAnd/src/com/osmand/activities/DownloadIndexActivity.java @@ -73,8 +73,9 @@ public class DownloadIndexActivity extends ListActivity { try { log.debug("Start loading list of index files"); //$NON-NLS-1$ Map indexFiles = DownloaderIndexFromGoogleCode.getIndexFiles(new String[] { IndexConstants.ADDRESS_INDEX_EXT, - IndexConstants.POI_INDEX_EXT }, new String[] { - IndexConstants.ADDRESS_TABLE_VERSION + "", IndexConstants.POI_TABLE_VERSION + "" }); //$NON-NLS-1$//$NON-NLS-2$ + IndexConstants.POI_INDEX_EXT, IndexConstants.TRANSPORT_INDEX_EXT, }, new String[] { + IndexConstants.ADDRESS_TABLE_VERSION + "", IndexConstants.POI_TABLE_VERSION + "",//$NON-NLS-1$//$NON-NLS-2$ + IndexConstants.TRANSPORT_TABLE_VERSION + "",}); //$NON-NLS-1$ if (indexFiles != null && !indexFiles.isEmpty()) { return indexFiles; } else { @@ -116,6 +117,9 @@ public class DownloadIndexActivity extends ListActivity { } else if(key.endsWith(IndexConstants.POI_INDEX_EXT)){ parent = new File(Environment.getExternalStorageDirectory(), ResourceManager.POI_PATH); regionName += IndexConstants.POI_INDEX_EXT; + } else if(key.endsWith(IndexConstants.TRANSPORT_INDEX_EXT)){ + parent = new File(Environment.getExternalStorageDirectory(), ResourceManager.TRANSPORT_PATH); + regionName += IndexConstants.TRANSPORT_INDEX_EXT; } if(parent != null){ parent.mkdirs(); @@ -150,6 +154,8 @@ public class DownloadIndexActivity extends ListActivity { ResourceManager.getResourceManager().indexingAddress(impl, warnings, file); } else if(file.getName().endsWith(IndexConstants.POI_INDEX_EXT)){ ResourceManager.getResourceManager().indexingPoi(impl, warnings, file); + } else if(file.getName().endsWith(IndexConstants.TRANSPORT_INDEX_EXT)){ + ResourceManager.getResourceManager().indexingTransport(impl, warnings, file); } if(warnings.isEmpty()){ showWarning(getString(R.string.download_index_success)); @@ -200,7 +206,15 @@ public class DownloadIndexActivity extends ListActivity { TextView description = (TextView) row.findViewById(R.id.download_descr); Entry e = getItem(position); int l = e.getKey().lastIndexOf('_'); - String s = e.getKey().endsWith(IndexConstants.POI_INDEX_EXT) ? getString(R.string.poi) : getString(R.string.address); + String s = ""; //$NON-NLS-1$ + if(e.getKey().endsWith(IndexConstants.POI_INDEX_EXT)){ + s = getString(R.string.poi); + } else if(e.getKey().endsWith(IndexConstants.ADDRESS_INDEX_EXT)){ + s = getString(R.string.address); + } else if(e.getKey().endsWith(IndexConstants.TRANSPORT_INDEX_EXT)){ + s = "Transport"; + } + item.setText(s + "\n " + e.getKey().substring(0, l)); //$NON-NLS-1$ description.setText(e.getValue().replace(':', '\n')); return row; diff --git a/OsmAnd/src/com/osmand/activities/EditingPOIActivity.java b/OsmAnd/src/com/osmand/activities/EditingPOIActivity.java index be848d8d0e..f8ac6de2bf 100644 --- a/OsmAnd/src/com/osmand/activities/EditingPOIActivity.java +++ b/OsmAnd/src/com/osmand/activities/EditingPOIActivity.java @@ -448,7 +448,7 @@ public class EditingPOIActivity { } private void updateNodeInIndexes(String action, Node n){ - List repos = ResourceManager.getResourceManager().searchRepositories(n.getLatitude(), n.getLongitude()); + List repos = ResourceManager.getResourceManager().searchAmenityRepositories(n.getLatitude(), n.getLongitude()); if(DELETE_ACTION.equals(action)){ for(AmenityIndexRepository r: repos){ r.deleteAmenity(n.getId()); diff --git a/OsmAnd/src/com/osmand/activities/MapActivity.java b/OsmAnd/src/com/osmand/activities/MapActivity.java index 12103bcdb8..9060fafbb1 100644 --- a/OsmAnd/src/com/osmand/activities/MapActivity.java +++ b/OsmAnd/src/com/osmand/activities/MapActivity.java @@ -72,6 +72,7 @@ import com.osmand.views.POIMapLayer; import com.osmand.views.PointLocationLayer; import com.osmand.views.PointNavigationLayer; import com.osmand.views.RouteLayer; +import com.osmand.views.TransportStopsLayer; public class MapActivity extends Activity implements LocationListener, IMapLocationListener, SensorEventListener { @@ -95,6 +96,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat private RouteLayer routeLayer; private OsmBugsLayer osmBugsLayer; private POIMapLayer poiMapLayer; + private TransportStopsLayer transportStopsLayer; private PointLocationLayer locationLayer; private PointNavigationLayer navigationLayer; private MapInfoLayer mapInfoLayer; @@ -172,13 +174,16 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat osmBugsLayer = new OsmBugsLayer(this); // 3. poi layer poiMapLayer = new POIMapLayer(); - // 4. point navigation layer + // 4. poi layer + transportStopsLayer = new TransportStopsLayer(); + mapView.addLayer(transportStopsLayer); + // 5. point navigation layer navigationLayer = new PointNavigationLayer(); mapView.addLayer(navigationLayer); - // 5. point location layer + // 6. point location layer locationLayer = new PointLocationLayer(); mapView.addLayer(locationLayer); - // 6. map info layer + // 7. map info layer mapInfoLayer = new MapInfoLayer(this, routeLayer); mapView.addLayer(mapInfoLayer); @@ -778,7 +783,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat Toast.makeText(this, getString(R.string.update_poi_is_not_available_for_zoom), Toast.LENGTH_SHORT).show(); return; } - final List repos = ResourceManager.getResourceManager().searchRepositories(latitude, longitude); + final List repos = ResourceManager.getResourceManager().searchAmenityRepositories(latitude, longitude); if(repos.isEmpty()){ Toast.makeText(this, getString(R.string.update_poi_no_offline_poi_index), Toast.LENGTH_SHORT).show(); return; @@ -918,5 +923,4 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat } - -} \ No newline at end of file +} diff --git a/OsmAnd/src/com/osmand/views/OsmBugsLayer.java b/OsmAnd/src/com/osmand/views/OsmBugsLayer.java index 9e26552293..ce5fb62be4 100644 --- a/OsmAnd/src/com/osmand/views/OsmBugsLayer.java +++ b/OsmAnd/src/com/osmand/views/OsmBugsLayer.java @@ -237,7 +237,7 @@ public class OsmBugsLayer implements OsmandMapLayer { int y = view.getRotatedMapYForPoint(n.getLatitude(), n.getLongitude()); if (Math.abs(x - ex) <= radius && Math.abs(y - ey) <= radius) { String format = "Bug : " + n.getName(); //$NON-NLS-1$ - Toast.makeText(view.getContext(), format, Toast.LENGTH_SHORT).show(); + Toast.makeText(view.getContext(), format, Toast.LENGTH_LONG).show(); return true; } } diff --git a/OsmAnd/src/com/osmand/views/TransportStopsLayer.java b/OsmAnd/src/com/osmand/views/TransportStopsLayer.java new file mode 100644 index 0000000000..db9028fbed --- /dev/null +++ b/OsmAnd/src/com/osmand/views/TransportStopsLayer.java @@ -0,0 +1,151 @@ +package com.osmand.views; + +import java.util.ArrayList; +import java.util.List; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.Rect; +import android.graphics.RectF; +import android.widget.Toast; + +import com.osmand.OsmandSettings; +import com.osmand.ResourceManager; +import com.osmand.TransportIndexRepository; +import com.osmand.data.TransportStop; +import com.osmand.osm.MapUtils; + +public class TransportStopsLayer implements OsmandMapLayer { + private static final int startZoom = 12; + + + private Paint pointAltUI; + private OsmandMapTileView view; + private List objects = new ArrayList(); + + private ResourceManager resourceManager; + + + @Override + public void initLayer(OsmandMapTileView view) { + this.view = view; + + pointAltUI = new Paint(); + pointAltUI.setColor(Color.rgb(0, 0, 255)); + pointAltUI.setAlpha(200); + pointAltUI.setAntiAlias(true); + resourceManager = ResourceManager.getResourceManager(); + pixRect.set(0, 0, view.getWidth(), view.getHeight()); + } + + public TransportStop getFromPoint(PointF point){ + if (objects != null) { + int ex = (int) point.x; + int ey = (int) point.y; + int radius = getRadiusPoi(view.getZoom()) * 3 / 2; + try { + for (int i = 0; i < objects.size(); i++) { + TransportStop n = objects.get(i); + int x = view.getRotatedMapXForPoint(n.getLocation().getLatitude(), n.getLocation().getLongitude()); + int y = view.getRotatedMapYForPoint(n.getLocation().getLatitude(), n.getLocation().getLongitude()); + if (Math.abs(x - ex) <= radius && Math.abs(y - ey) <= radius) { + return n; + } + } + } catch (IndexOutOfBoundsException e) { + // that's really rare case, but is much efficient than introduce synchronized block + } + } + return null; + } + + + + + public int getTileSize(){ + return view.getTileSize(); + } + + + @Override + public boolean onTouchEvent(PointF point) { + TransportStop n = getFromPoint(point); + if(n != null){ + StringBuilder text = new StringBuilder(250); + text.append("Stop").append(" : ").append(n.getName(OsmandSettings.usingEnglishNames(view.getContext()))); //$NON-NLS-2$ + text.append("\n").append("Routes").append(" : "); //$NON-NLS-1$//$NON-NLS-3$ + List reps = ResourceManager.getResourceManager().searchTransportRepositories(n.getLocation().getLatitude(), n.getLocation().getLongitude()); + if(!reps.isEmpty()){ + List l; + if(OsmandSettings.usingEnglishNames(view.getContext())){ + l = reps.get(0).getRouteDescriptionsForStop(n, "{1} {0} - {3}"); //$NON-NLS-1$ + } else { + l = reps.get(0).getRouteDescriptionsForStop(n, "{1} {0} - {2}"); //$NON-NLS-1$ + } + for(String s : l){ + text.append("\n").append(s); //$NON-NLS-1$ + } + } + Toast.makeText(view.getContext(), text.toString(), Toast.LENGTH_LONG).show(); + return true; + } + return false; + } + + public int getRadiusPoi(int zoom){ + if(zoom < startZoom){ + return 0; + } else if(zoom <= 15){ + return 7; + } else if(zoom == 16){ + return 10; + } else if(zoom == 17){ + return 14; + } else { + return 18; + } + } + + Rect pixRect = new Rect(); + RectF tileRect = new RectF(); + + @Override + public void onDraw(Canvas canvas) { + if (view.getZoom() >= startZoom) { + 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.getZoom(), tileRect.top); + double leftLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.left); + double bottomLatitude = MapUtils.getLatitudeFromTile(view.getZoom(), tileRect.bottom); + double rightLongitude = MapUtils.getLongitudeFromTile(view.getZoom(), tileRect.right); + + objects.clear(); + resourceManager.searchTransportAsync(topLatitude, leftLongitude, bottomLatitude, rightLongitude, view.getZoom(), objects); + for (TransportStop o : objects) { + int x = view.getMapXForPoint(o.getLocation().getLongitude()); + int y = view.getMapYForPoint(o.getLocation().getLatitude()); + canvas.drawCircle(x, y, getRadiusPoi(view.getZoom()), pointAltUI); + } + + } + } + + @Override + public void destroyLayer() { + } + + @Override + public boolean drawInScreenPixels() { + return false; + } + + @Override + public boolean onLongPressEvent(PointF point) { + // TODO open search transport + return false; + } + +}