diff --git a/DataExtractionOSM/.classpath b/DataExtractionOSM/.classpath index ff1c24c60c..8d48231432 100644 --- a/DataExtractionOSM/.classpath +++ b/DataExtractionOSM/.classpath @@ -5,5 +5,6 @@ + diff --git a/DataExtractionOSM/lib/sqlitejdbc-v056.jar b/DataExtractionOSM/lib/sqlitejdbc-v056.jar new file mode 100644 index 0000000000..f95d90eb07 Binary files /dev/null and b/DataExtractionOSM/lib/sqlitejdbc-v056.jar differ diff --git a/DataExtractionOSM/src/com/osmand/data/preparation/DataIndexBuilder.java b/DataExtractionOSM/src/com/osmand/data/preparation/DataIndexBuilder.java index 8e5c198f56..b690ec96ab 100644 --- a/DataExtractionOSM/src/com/osmand/data/preparation/DataIndexBuilder.java +++ b/DataExtractionOSM/src/com/osmand/data/preparation/DataIndexBuilder.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.zip.ZipEntry; @@ -59,7 +60,7 @@ public class DataIndexBuilder { } - public DataIndexBuilder buildPOI() throws XMLStreamException, IOException { + public DataIndexBuilder buildPOI() throws XMLStreamException, IOException, SQLException { List list = region.getAmenityManager().getAllObjects(); List interestedObjects = new ArrayList(list.size()); @@ -75,6 +76,8 @@ public class DataIndexBuilder { } OsmStorageWriter writer = new OsmStorageWriter(); writer.saveLuceneIndex(new File(workingDir, "lucene"), region); + writer.saveSQLLitePOIIndex(new File(workingDir, "POI/"+region.getName()+".db"), region); + return this; } diff --git a/DataExtractionOSM/src/com/osmand/osm/io/OsmStorageWriter.java b/DataExtractionOSM/src/com/osmand/osm/io/OsmStorageWriter.java index b616066797..c3d6c1e52a 100644 --- a/DataExtractionOSM/src/com/osmand/osm/io/OsmStorageWriter.java +++ b/DataExtractionOSM/src/com/osmand/osm/io/OsmStorageWriter.java @@ -29,6 +29,11 @@ import static com.osmand.osm.io.OsmIndexStorage.OSMAND_VERSION; import java.io.File; import java.io.IOException; import java.io.OutputStream; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -212,11 +217,56 @@ public class OsmStorageWriter { //for (Entry entry:amenity.getNode().getTags().entrySet()) { // document.add(new Field(entry.getKey(),entry.getValue(),Store.YES, Index.NOT_ANALYZED)); //} - writer.addDocument(document); } + public void saveSQLLitePOIIndex(File file, Region region) throws SQLException{ + long now = System.currentTimeMillis(); + try { + Class.forName("org.sqlite.JDBC"); + } catch (ClassNotFoundException e) { + log.error("Illegal configuration", e); + throw new IllegalStateException(e); + } + Connection conn = DriverManager.getConnection("jdbc:sqlite:"+file.getAbsolutePath()); + + final int batchSize = 500; + try { + Statement stat = conn.createStatement(); + stat.executeUpdate("create table poi (id long, latitude double, longitude double, name, type, subtype);"); + stat.executeUpdate("create index LatLonIndex ON poi (latitude, longitude);"); + PreparedStatement prep = conn.prepareStatement( + "insert into poi values (?, ?, ?, ?, ? ,? );"); + conn.setAutoCommit(false); + int currentCount = 0; + for (Amenity a : region.getAmenityManager().getAllObjects()) { + prep.setLong(1, a.getId()); + prep.setDouble(2, a.getLocation().getLatitude()); + prep.setDouble(3, a.getLocation().getLongitude()); + prep.setString(4, a.getName()); + prep.setString(5, AmenityType.valueToString(a.getType())); + prep.setString(6, a.getSubType()); + prep.addBatch(); + currentCount++; + if(currentCount >= batchSize){ + prep.executeBatch(); + currentCount = 0; + } + + } + if(currentCount > 0){ + prep.executeBatch(); + } + conn.setAutoCommit(true); + } finally { + conn.close(); + log.info(String.format("Indexing sqllite done in %s ms.", System.currentTimeMillis() - now)); + } + + } + + public void savePOIIndex(OutputStream output, Region region) throws XMLStreamException, IOException { PropertyManager propertyManager = new PropertyManager(PropertyManager.CONTEXT_WRITER); XMLStreamWriter streamWriter = new XMLStreamWriterImpl(output, propertyManager); diff --git a/DataExtractionOSM/src/com/osmand/swing/OsmExtractionUI.java b/DataExtractionOSM/src/com/osmand/swing/OsmExtractionUI.java index 1bf605c3aa..14d7fbb101 100644 --- a/DataExtractionOSM/src/com/osmand/swing/OsmExtractionUI.java +++ b/DataExtractionOSM/src/com/osmand/swing/OsmExtractionUI.java @@ -13,6 +13,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -372,6 +373,8 @@ public class OsmExtractionUI implements IMapLocationListener { JOptionPane pane = new JOptionPane(msg); JDialog dialog = pane.createDialog(frame, "Generation data"); dialog.setVisible(true); + } catch (SQLException e1) { + throw new IllegalArgumentException(e1); } catch (XMLStreamException e1) { throw new IllegalArgumentException(e1); } catch (IOException e1) { diff --git a/OsmAnd/src/com/osmand/OsmSQLLiteRepository.java b/OsmAnd/src/com/osmand/OsmSQLLiteRepository.java new file mode 100644 index 0000000000..9f1a5c9efa --- /dev/null +++ b/OsmAnd/src/com/osmand/OsmSQLLiteRepository.java @@ -0,0 +1,122 @@ +package com.osmand; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.logging.Log; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; + +import com.osmand.data.Amenity; +import com.osmand.data.Amenity.AmenityType; + +public class OsmSQLLiteRepository { + private static final Log log = LogUtil.getLog(OsmSQLLiteRepository.class); + + private SQLiteDatabase db; + + private List cachedAmenities = null; + private double cTopLatitude; + private double cBottomLatitude; + private double cLeftLongitude; + private double cRightLongitude; + + private boolean isLoading = false; + + protected synchronized void loadAmenitiesInAnotherThread(final double topLatitude, final double leftLongitude, final double bottomLatitude, final double rightLongitude){ + isLoading = true; + new Thread(new Runnable(){ + + @Override + public void run() { + try { + cachedAmenities = internalSearch(topLatitude, leftLongitude, bottomLatitude, rightLongitude); + cTopLatitude = topLatitude; + cLeftLongitude = leftLongitude; + cBottomLatitude = bottomLatitude ; + cRightLongitude = rightLongitude; + } finally { + synchronized (this) { + isLoading = false; + } + } + } + }, "Searching in index...").start(); + } + + + private List internalSearch(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude){ + long now = System.currentTimeMillis(); + Cursor query = db.query("poi", null, "? < latitude AND latitude < ? AND ? < longitude AND longitude < ?", + new String[]{Double.toString(bottomLatitude), + Double.toString(topLatitude), Double.toString(leftLongitude), Double.toString(rightLongitude)}, null, null, null); + List amenities = new ArrayList(); + int idIndex = query.getColumnIndex("id"); + int latitudeIndex = query.getColumnIndex("latitude"); + int longitudeIndex = query.getColumnIndex("longitude"); + int nameIndex = query.getColumnIndex("name"); + int typeIndex = query.getColumnIndex("type"); + int subtypeIndex = query.getColumnIndex("subtype"); + if(query.moveToFirst()){ + do { + Amenity am = new Amenity(); + if(idIndex != -1){ + am.setId(query.getLong(idIndex)); + } + if(latitudeIndex != -1 && longitudeIndex != -1){ + am.setLocation(query.getDouble(latitudeIndex), query.getDouble(longitudeIndex)); + } + if(nameIndex != -1){ + am.setName(query.getString(nameIndex)); + } + if(typeIndex != -1){ + am.setType(AmenityType.fromString(query.getString(typeIndex))); + } + if(subtypeIndex != -1){ + am.setSubType(query.getString(subtypeIndex)); + } + amenities.add(am); + } while(query.moveToNext()); + } + query.deactivate(); + + if (log.isDebugEnabled()) { + log.debug(String.format("Search for %s done in %s ms found %s.", + topLatitude + " " + leftLongitude, System.currentTimeMillis() - now, amenities.size())); + } + return amenities; + } + public synchronized List searchAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude) { + if (db == null) { + return Collections.emptyList(); + } + if (cTopLatitude >= topLatitude && cLeftLongitude <= leftLongitude && cRightLongitude >= rightLongitude + && cBottomLatitude <= bottomLatitude) { + return cachedAmenities; + } + if(!isLoading){ + double h = (topLatitude - bottomLatitude); + double w = (rightLongitude - leftLongitude); + topLatitude += h; + leftLongitude -= w; + bottomLatitude -= h; + rightLongitude += w; + loadAmenitiesInAnotherThread(topLatitude, leftLongitude, bottomLatitude, rightLongitude); + } + return Collections.emptyList(); + } + + public void initialize(final IProgress progress, File file) { + long start = System.currentTimeMillis(); + db = SQLiteDatabase.openOrCreateDatabase(file, null); + if (log.isDebugEnabled()) { + log.debug("Initializing db " + file.getAbsolutePath() + " " + (System.currentTimeMillis() - start) + "ms"); + } + } + + + +} diff --git a/OsmAnd/src/com/osmand/ResourceManager.java b/OsmAnd/src/com/osmand/ResourceManager.java index b9121f7f74..aaf90992b9 100644 --- a/OsmAnd/src/com/osmand/ResourceManager.java +++ b/OsmAnd/src/com/osmand/ResourceManager.java @@ -74,6 +74,8 @@ public class ResourceManager { protected OsmLuceneRepository amenityIndexSearcher = new OsmLuceneRepository(); + protected OsmSQLLiteRepository amenityRepository = new OsmSQLLiteRepository(); + public ResourceManager() { // TODO start/stop this thread when needed? @@ -280,6 +282,16 @@ public class ResourceManager { } }); + + File file = new File(Environment.getExternalStorageDirectory(), POI_PATH); + if (file.exists() && file.canRead()) { + for (File f : file.listFiles()) { + if(f.getName().endsWith(".db")){ + progress.startTask("Indexing poi " + f.getName(), -1); + amenityRepository.initialize(progress, f); + } + } + } } } @@ -313,6 +325,10 @@ public class ResourceManager { return poiIndex; } + public OsmSQLLiteRepository getAmenityRepository() { + return amenityRepository; + } + public OsmLuceneRepository getAmenityIndexSearcher(){ return amenityIndexSearcher; diff --git a/OsmAnd/src/com/osmand/views/POIMapLayer.java b/OsmAnd/src/com/osmand/views/POIMapLayer.java index 0559d48081..8ec70ebd15 100644 --- a/OsmAnd/src/com/osmand/views/POIMapLayer.java +++ b/OsmAnd/src/com/osmand/views/POIMapLayer.java @@ -8,6 +8,7 @@ import android.graphics.Paint; import android.view.MotionEvent; import android.widget.Toast; +import com.osmand.OsmSQLLiteRepository; import com.osmand.ResourceManager; import com.osmand.data.Amenity; import com.osmand.data.DataTileManager; @@ -115,8 +116,20 @@ public class POIMapLayer implements OsmandMapLayer { canvas.drawCircle(x, y, getRadiusPoi(view.getZoom()), pointAltUI); } } + + OsmSQLLiteRepository sqlLite = ResourceManager.getResourceManager().getAmenityRepository(); + if (sqlLite != null) { + objects = sqlLite.searchAmenities(topLatitude, leftLongitude, bottomLatitude, rightLongitude); + for (Amenity o : objects) { + double tileX = MapUtils.getTileNumberX(view.getZoom(), o.getLocation().getLongitude()); + int x = (int) ((tileX - xTileLeft) * getTileSize()); + double tileY = MapUtils.getTileNumberY(view.getZoom(), o.getLocation().getLatitude()); + int y = (int) ((tileY - yTileUp) * getTileSize()); + canvas.drawCircle(x, y, getRadiusPoi(view.getZoom()), pointAltUI); + } + } if (nodeManager != null) { - objects = nodeManager.getObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude); + List objects = nodeManager.getObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude); for (Amenity o : objects) { double tileX = MapUtils.getTileNumberX(view.getZoom(), o.getLocation().getLongitude()); int x = (int) ((tileX - xTileLeft) * getTileSize());