From eb7abdd0b87ce51a25dc9e106b13168e65cc664f Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sat, 1 Oct 2011 09:00:00 +0200 Subject: [PATCH] Search by name improvement --- .../binary/BinaryMapPoiReaderAdapter.java | 63 ++++++++++++++----- .../data/preparation/IndexPoiCreator.java | 2 - OsmAnd/res/values/strings.xml | 1 + .../src/net/osmand/plus/ResourceManager.java | 13 ++++ .../search/SearchPoiFilterActivity.java | 11 ++++ 5 files changed, 73 insertions(+), 17 deletions(-) diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapPoiReaderAdapter.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapPoiReaderAdapter.java index ba9d71d491..3a846b5fec 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapPoiReaderAdapter.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapPoiReaderAdapter.java @@ -8,6 +8,8 @@ import java.io.IOException; import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import org.apache.commons.logging.Log; @@ -32,6 +34,7 @@ public class BinaryMapPoiReaderAdapter { public static final int SHIFT_BITS_CATEGORY = 7; private static final int CATEGORY_MASK = (1 << SHIFT_BITS_CATEGORY) - 1 ; private static final int ZOOM_TO_SKIP_FILTER = 3; + private static final int BUCKET_SEARCH_BY_NAME = 5; public static class PoiRegion extends BinaryIndexPart { @@ -161,7 +164,7 @@ public class BinaryMapPoiReaderAdapter { } protected void searchPoiByName( PoiRegion region, SearchRequest req) throws IOException { - TIntArrayList offsets = new TIntArrayList(); + TIntLongHashMap offsets = new TIntLongHashMap(); Collator instance = Collator.getInstance(); instance.setStrength(Collator.PRIMARY); CollatorStringMatcher matcher = new CollatorStringMatcher(instance, req.nameQuery, @@ -180,16 +183,42 @@ public class BinaryMapPoiReaderAdapter { case OsmandOdb.OsmAndPoiIndex.NAMEINDEX_FIELD_NUMBER : int length = readInt(); int oldLimit = codedIS.pushLimit(length); + // here offsets are sorted by distance offsets = readPoiNameIndex(instance, req.nameQuery, req); codedIS.popLimit(oldLimit); break; case OsmandOdb.OsmAndPoiIndex.POIDATA_FIELD_NUMBER : // also offsets can be randomly skipped by limit - offsets.sort(); + Integer[] offKeys = new Integer[offsets.size()]; + if (offsets.size() > 0) { + int[] keys = offsets.keys(); + for (int i = 0; i < keys.length; i++) { + offKeys[i] = keys[i]; + } + final TIntLongHashMap foffsets = offsets; + Arrays.sort(offKeys, new Comparator() { + @Override + public int compare(Integer object1, Integer object2) { + return Double.compare(foffsets.get(object1), foffsets.get(object2)); + } + }); + int p = 0; + for (int i = BUCKET_SEARCH_BY_NAME;; i += BUCKET_SEARCH_BY_NAME) { + if (i > offKeys.length) { + Arrays.sort(offKeys, p, offKeys.length); + break; + } else { + Arrays.sort(offKeys, p, i); + } + p = i; + } + } + + LOG.info("Searched poi structure in "+(System.currentTimeMillis() - time) + - "ms. Found " + offsets.size() +" subtress"); - for (int j = 0; j < offsets.size(); j++) { - codedIS.seek(offsets.get(j) + indexOffset); + "ms. Found " + offKeys.length +" subtress"); + for (int j = 0; j < offKeys.length; j++) { + codedIS.seek(offKeys[j] + indexOffset); int len = readInt(); int oldLim = codedIS.pushLimit(len); readPoiData(matcher, req, region); @@ -209,8 +238,8 @@ public class BinaryMapPoiReaderAdapter { } } - private TIntArrayList readPoiNameIndex(Collator instance, String query, SearchRequest req) throws IOException { - TIntArrayList offsets = new TIntArrayList(); + private TIntLongHashMap readPoiNameIndex(Collator instance, String query, SearchRequest req) throws IOException { + TIntLongHashMap offsets = new TIntLongHashMap(); TIntArrayList dataOffsets = null; while(true){ int t = codedIS.readTag(); @@ -233,7 +262,7 @@ public class BinaryMapPoiReaderAdapter { codedIS.seek(dataOffsets.get(i) + offset); int len = codedIS.readRawVarint32(); int oldLim = codedIS.pushLimit(len); - readPoiNameIndexData(offsets); + readPoiNameIndexData(offsets, req); codedIS.popLimit(oldLim); if (req.isCancelled()) { codedIS.skipRawBytes(codedIS.getBytesUntilLimit()); @@ -251,7 +280,7 @@ public class BinaryMapPoiReaderAdapter { } - private void readPoiNameIndexData(TIntArrayList offsets) throws IOException { + private void readPoiNameIndexData(TIntLongHashMap offsets, SearchRequest req) throws IOException { while(true){ int t = codedIS.readTag(); int tag = WireFormat.getTagFieldNumber(t); @@ -261,7 +290,7 @@ public class BinaryMapPoiReaderAdapter { case OsmandOdb.OsmAndPoiNameIndexData.ATOMS_FIELD_NUMBER : int len = codedIS.readRawVarint32(); int oldLim = codedIS.pushLimit(len); - readPoiNameIndexDataAtom(offsets); + readPoiNameIndexDataAtom(offsets, req); codedIS.popLimit(oldLim); break; default: @@ -272,24 +301,28 @@ public class BinaryMapPoiReaderAdapter { } - private void readPoiNameIndexDataAtom(TIntArrayList offsets) throws IOException { + private void readPoiNameIndexDataAtom(TIntLongHashMap offsets, SearchRequest req) throws IOException { while(true){ int t = codedIS.readTag(); int tag = WireFormat.getTagFieldNumber(t); + int x = 0; + int y = 0; + int zoom = 15; switch (tag) { case 0: return; case OsmandOdb.OsmAndPoiNameIndexDataAtom.X_FIELD_NUMBER : - /*int x = */codedIS.readUInt32(); + x = codedIS.readUInt32(); break; case OsmandOdb.OsmAndPoiNameIndexDataAtom.Y_FIELD_NUMBER : - /*int y = */codedIS.readUInt32(); + y = codedIS.readUInt32(); break; case OsmandOdb.OsmAndPoiNameIndexDataAtom.ZOOM_FIELD_NUMBER : - /*int zoom = */codedIS.readUInt32(); + zoom = codedIS.readUInt32(); break; case OsmandOdb.OsmAndPoiNameIndexDataAtom.SHIFTTO_FIELD_NUMBER : - offsets.add(readInt()); + long d = Math.abs(req.x - (x << (31 - zoom))) + Math.abs(req.y - (y << (31 - zoom))); + offsets.put(readInt(), d); break; default: skipUnknownField(t); diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java index 70292f71e4..89851452d2 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java @@ -558,8 +558,6 @@ public class IndexPoiCreator extends AbstractIndexPartCreator { // TODO support cancelling poi search request! Do it in another thread (Check is cancelled()!!!) // TODO make more discrete POI Filter // TODO implement UI to show matching by name subcategories - // TODO Warning if there is no poi files to search by name - // TODO sort blocks by distance in binary reader long time = System.currentTimeMillis(); IndexPoiCreator poiCreator = new IndexPoiCreator(); // String fileSqlte = "/home/victor/projects/OsmAnd/data/osm-gen/POI/Ru-mow.poi.odb"; diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 8c03e5d701..1079f1d2b1 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -1,5 +1,6 @@ + Local data to search POI is not present. Search by name The poi data file \'%1$s\' is deprecated and can be deleted. Local file to maintain poi changes not found and could not be created. diff --git a/OsmAnd/src/net/osmand/plus/ResourceManager.java b/OsmAnd/src/net/osmand/plus/ResourceManager.java index 79efe22674..53b6e19bdf 100644 --- a/OsmAnd/src/net/osmand/plus/ResourceManager.java +++ b/OsmAnd/src/net/osmand/plus/ResourceManager.java @@ -604,6 +604,19 @@ public class ResourceManager { return amenities; } + public boolean containsAmenityRepositoryToSearch(boolean searchByName){ + for (AmenityIndexRepository index : amenityRepositories) { + if(searchByName){ + if(index instanceof AmenityIndexRepositoryBinary){ + return true; + } + } else { + return true; + } + } + return false; + } + public List searchAmenitiesByName(String searchQuery, double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, double lat, double lon, ResultMatcher matcher) { diff --git a/OsmAnd/src/net/osmand/plus/activities/search/SearchPoiFilterActivity.java b/OsmAnd/src/net/osmand/plus/activities/search/SearchPoiFilterActivity.java index 4755ed6996..415b2bb5cd 100644 --- a/OsmAnd/src/net/osmand/plus/activities/search/SearchPoiFilterActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/search/SearchPoiFilterActivity.java @@ -7,10 +7,13 @@ import java.util.ArrayList; import java.util.List; import net.osmand.osm.LatLon; +import net.osmand.plus.NameFinderPoiFilter; import net.osmand.plus.OsmandSettings; import net.osmand.plus.PoiFilter; import net.osmand.plus.PoiFiltersHelper; import net.osmand.plus.R; +import net.osmand.plus.ResourceManager; +import net.osmand.plus.SearchByNameFilter; import net.osmand.plus.activities.EditPOIFilterActivity; import net.osmand.plus.activities.OsmandApplication; import android.app.ListActivity; @@ -25,6 +28,7 @@ import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; +import android.widget.Toast; /** @@ -109,6 +113,13 @@ public class SearchPoiFilterActivity extends ListActivity { showEditActivity(filter); return; } + if(!(filter instanceof NameFinderPoiFilter)){ + ResourceManager rm = ((OsmandApplication) getApplication()).getResourceManager(); + if(!rm.containsAmenityRepositoryToSearch(filter instanceof SearchByNameFilter)){ + Toast.makeText(this, R.string.data_to_search_poi_not_available, Toast.LENGTH_LONG); + return; + } + } final Intent newIntent = new Intent(SearchPoiFilterActivity.this, SearchPOIActivity.class); newIntent.putExtra(SearchPOIActivity.AMENITY_FILTER, filter.getFilterId()); updateIntentToLaunch(newIntent);