diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java index 60479811fe..55253edf10 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java @@ -21,6 +21,7 @@ import net.osmand.binary.BinaryMapAddressReaderAdapter.AddressRegion; import net.osmand.binary.BinaryMapPoiReaderAdapter.PoiRegion; import net.osmand.binary.BinaryMapTransportReaderAdapter.TransportIndex; import net.osmand.data.Amenity; +import net.osmand.data.AmenityType; import net.osmand.data.Building; import net.osmand.data.City; import net.osmand.data.MapObject; @@ -975,9 +976,10 @@ public class BinaryMapIndexReader { } - public static SearchRequest buildSearchPoiRequest(int sleft, int sright, int stop, int sbottom, int zoom){ + public static SearchRequest buildSearchPoiRequest(int sleft, int sright, int stop, int sbottom, int limit, int zoom){ SearchRequest request = new SearchRequest(); request.left = sleft; + request.limit = limit; request.right = sright; request.top = stop; request.bottom = sbottom; @@ -1015,6 +1017,12 @@ public class BinaryMapIndexReader { } + public static interface SearchPoiTypeFilter { + + public boolean accept(AmenityType type, String subcategory); + + } + public static class SearchRequest { // 31 zoom tiles int left = 0; @@ -1027,6 +1035,7 @@ public class BinaryMapIndexReader { TIntArrayList cacheCoordinates = new TIntArrayList(); TIntArrayList cacheTypes = new TIntArrayList(); SearchFilter searchFilter = null; + SearchPoiTypeFilter poiTypeFilter = null; // TRACE INFO int numberOfVisitedObjects = 0; @@ -1045,6 +1054,14 @@ public class BinaryMapIndexReader { this.searchFilter = searchFilter; } + public void setPoiTypeFilter(SearchPoiTypeFilter poiTypeFilter) { + this.poiTypeFilter = poiTypeFilter; + } + + public SearchPoiTypeFilter getPoiTypeFilter() { + return poiTypeFilter; + } + public List getSearchResults() { return searchResults; } @@ -1207,11 +1224,18 @@ public class BinaryMapIndexReader { // System.out.println(poiRegion.categories.get(i)); // System.out.println(" " + poiRegion.subcategories.get(i)); // } - int sleft = MapUtils.get31TileNumberX(37.72); - int sright = MapUtils.get31TileNumberX(37.727); + int sleft = MapUtils.get31TileNumberX(37.5); + int sright = MapUtils.get31TileNumberX(37.9); int stop = MapUtils.get31TileNumberY(55.814); int sbottom = MapUtils.get31TileNumberY(55.81); - List results = reader.searchPoi(buildSearchPoiRequest(sleft, sright, stop, sbottom, 15)); + SearchRequest req = buildSearchPoiRequest(sleft, sright, stop, sbottom, 15); + req.setPoiTypeFilter(new SearchPoiTypeFilter() { + @Override + public boolean accept(AmenityType type, String subcategory) { + return type == AmenityType.TRANSPORTATION && "fuel".equals(subcategory); + } + }); + List results = reader.searchPoi(req); for(Amenity a : results){ System.out.println(a.getType() + " " + a.getSubType() + " " + a.getName() + " " + a.getLocation()); } diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexWriter.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexWriter.java index eb196937f8..c6381e1986 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexWriter.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexWriter.java @@ -791,6 +791,21 @@ public class BinaryMapIndexWriter { return catIndexes; } + public void writePOICategories(TIntArrayList categories) throws IOException { + checkPeekState(POI_BOX); + OsmandOdb.OsmAndPoiCategories.Builder builder = OsmandOdb.OsmAndPoiCategories.newBuilder(); + int prev = 0; + categories.sort(); + for (int i = 0; i < categories.size(); i++) { + // avoid duplicates + if (i > 0 && prev != categories.get(i)) { + builder.addCategories(categories.get(i)); + prev = categories.get(i); + } + } + codedOutStream.writeMessage(OsmandOdb.OsmAndPoiBox.CATEGORIES_FIELD_NUMBER, builder.build()); + } + public void writePoiDataAtom(long id, int x24shift, int y24shift, String nameEn, String name, TIntArrayList types, String openingHours, String site, String phone) throws IOException { checkPeekState(POI_DATA); diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapPoiReaderAdapter.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapPoiReaderAdapter.java index e05a5b582a..5982a39f9f 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapPoiReaderAdapter.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapPoiReaderAdapter.java @@ -134,13 +134,13 @@ public class BinaryMapPoiReaderAdapter { case 0: return; case OsmandOdb.OsmAndCategoryTable.CATEGORY_FIELD_NUMBER : - String cat = codedIS.readString(); + String cat = codedIS.readString().intern(); region.categories.add(cat); region.categoriesType.add(AmenityType.fromString(cat)); region.subcategories.add(new ArrayList()); break; case OsmandOdb.OsmAndCategoryTable.SUBCATEGORIES_FIELD_NUMBER : - region.subcategories.get(region.subcategories.size() - 1).add(codedIS.readString()); + region.subcategories.get(region.subcategories.size() - 1).add(codedIS.readString().intern()); break; default: skipUnknownField(t); @@ -165,7 +165,7 @@ public class BinaryMapPoiReaderAdapter { case OsmandOdb.OsmAndPoiIndex.BOXES_FIELD_NUMBER : int length = readInt(); int oldLimit = codedIS.pushLimit(length); - readBoxField(left31, right31, top31, bottom31, 0, 0, 0, offsets, req); + readBoxField(left31, right31, top31, bottom31, 0, 0, 0, offsets, req, region); codedIS.popLimit(oldLimit); break; case OsmandOdb.OsmAndPoiIndex.POIDATA_FIELD_NUMBER : @@ -255,19 +255,25 @@ public class BinaryMapPoiReaderAdapter { am.setLocation(MapUtils.get31LatitudeY(y), MapUtils.get31LongitudeX(x)); break; case OsmandOdb.OsmAndPoiBoxDataAtom.CATEGORIES_FIELD_NUMBER : - // TODO support many amenities type + // TODO support many amenities type !! int cat = codedIS.readUInt32(); int subcatId = cat >> SHIFT_BITS_CATEGORY; int catId = cat & CATEGORY_MASK; - if(catId < region.categoriesType.size()){ - am.setType(region.categoriesType.get(catId)); + AmenityType type = AmenityType.OTHER; + String subtype = ""; + if (catId < region.categoriesType.size()) { + type = region.categoriesType.get(catId); List subcats = region.subcategories.get(catId); - if(subcatId < subcats.size()){ - am.setSubType(subcats.get(subcatId)); + if (subcatId < subcats.size()) { + subtype = subcats.get(subcatId); } - } else { - am.setType(AmenityType.OTHER); } + if (req.poiTypeFilter != null && !req.poiTypeFilter.accept(type, subtype)) { + codedIS.skipRawBytes(codedIS.getBytesUntilLimit()); + return; + } + am.setSubType(subtype); + am.setType(type); break; case OsmandOdb.OsmAndPoiBoxDataAtom.ID_FIELD_NUMBER : am.setId(codedIS.readUInt64()); @@ -293,9 +299,44 @@ public class BinaryMapPoiReaderAdapter { } } } + + private boolean checkCategories(SearchRequest req, PoiRegion region) throws IOException { + while(true){ + int t = codedIS.readTag(); + int tag = WireFormat.getTagFieldNumber(t); + switch (tag) { + case 0: + return false; + case OsmandOdb.OsmAndPoiCategories.CATEGORIES_FIELD_NUMBER: + AmenityType type = AmenityType.OTHER; + String subcat = ""; + int cat = codedIS.readUInt32(); + int subcatId = cat >> SHIFT_BITS_CATEGORY; + int catId = cat & CATEGORY_MASK; + if(catId < region.categoriesType.size()){ + type = region.categoriesType.get(catId); + List subcats = region.subcategories.get(catId); + if(subcatId < subcats.size()){ + subcat = subcats.get(subcatId); + } + } else { + type = AmenityType.OTHER; + } + if(req.poiTypeFilter.accept(type, subcat)){ + codedIS.skipRawBytes(codedIS.getBytesUntilLimit()); + return true; + } + + break; + default: + skipUnknownField(t); + break; + } + } + } private void readBoxField(int left31, int right31, int top31, int bottom31, - int px, int py, int pzoom, TIntArrayList offsets, SearchRequest req) throws IOException { + int px, int py, int pzoom, TIntArrayList offsets, SearchRequest req, PoiRegion region) throws IOException { req.numberOfReadSubtrees++; boolean checkBox = true; int zoom = pzoom; @@ -319,6 +360,20 @@ public class BinaryMapPoiReaderAdapter { case OsmandOdb.OsmAndPoiBox.TOP_FIELD_NUMBER: dy = codedIS.readSInt32(); break; + case OsmandOdb.OsmAndPoiBox.CATEGORIES_FIELD_NUMBER: + if(req.poiTypeFilter == null){ + skipUnknownField(t); + } else { + int length = codedIS.readRawVarint32(); + int oldLimit = codedIS.pushLimit(length); + boolean check = checkCategories(req, region); + codedIS.popLimit(oldLimit); + if(!check){ + codedIS.skipRawBytes(codedIS.getBytesUntilLimit()); + return; + } + } + break; case OsmandOdb.OsmAndPoiBox.SUBBOXES_FIELD_NUMBER: int x = dx + (px << (zoom - pzoom)); @@ -338,7 +393,7 @@ public class BinaryMapPoiReaderAdapter { } int length = readInt(); int oldLimit = codedIS.pushLimit(length); - readBoxField(left31, right31, top31, bottom31, x, y, zoom, offsets, req); + readBoxField(left31, right31, top31, bottom31, x, y, zoom, offsets, req, region); codedIS.popLimit(oldLimit); break; @@ -351,6 +406,5 @@ public class BinaryMapPoiReaderAdapter { } } } - } diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java index 741ab39ce4..e0877e673b 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexPoiCreator.java @@ -44,6 +44,8 @@ public class IndexPoiCreator extends AbstractIndexPartCreator { private PreparedStatement poiPreparedStatement; private static final int ZOOM_TO_SAVE_END = 16; private static final int ZOOM_TO_SAVE_START = 6; + private static final int ZOOM_TO_WRITE_CATEGORIES_START = 12; + private static final int ZOOM_TO_WRITE_CATEGORIES_END = 16; private List tempAmenityList = new ArrayList(); @@ -154,7 +156,6 @@ public class IndexPoiCreator extends AbstractIndexPartCreator { private void buildTypeIds(String category, String subcategory, Map> categories, Map catIndexes, TIntArrayList types) { - types.clear(); Map map = categories.get(category); if (map == null) { throw new IllegalArgumentException("Unknown category " + category); @@ -256,18 +257,21 @@ public class IndexPoiCreator extends AbstractIndexPartCreator { zoomToStart = zoomToStart + level; } - // write tree using stack + // 3.2 write tree using stack + PreparedStatement prepareStatement = poiConnection.prepareStatement("SELECT DISTINCT type, subtype FROM poi WHERE x >= ? AND x < ? AND y >= ? AND y < ?"); Map fpToWriteSeeks = new LinkedHashMap(); for (Tree subs : rootZoomsTree.getSubtrees()) { - writePoiBoxes(writer, subs, zoomToStart, fpToWriteSeeks); + writePoiBoxes(writer, subs, zoomToStart, fpToWriteSeeks, prepareStatement, + categories, catIndexes); } stat = rs.getStatement(); rs.close(); stat.close(); + prepareStatement.close(); // 4. write poi data - PreparedStatement prepareStatement = poiConnection + prepareStatement = poiConnection .prepareStatement("SELECT id, x, y, name_en, name, type, subtype, opening_hours, site, phone from poi " + "where x >= ? AND x < ? AND y >= ? AND y < ?"); TIntArrayList types = new TIntArrayList(); @@ -293,6 +297,7 @@ public class IndexPoiCreator extends AbstractIndexPartCreator { String name = rs.getString(5); String type = rs.getString(6); String subtype = rs.getString(7); + types.clear(); buildTypeIds(type, subtype, categories, catIndexes, types); String openingHours = rs.getString(8); @@ -313,15 +318,32 @@ public class IndexPoiCreator extends AbstractIndexPartCreator { } - private void writePoiBoxes(BinaryMapIndexWriter writer, Tree tree, int zoom, Map fpToWriteSeeks) throws IOException { + private void writePoiBoxes(BinaryMapIndexWriter writer, Tree tree, int zoom, Map fpToWriteSeeks, + PreparedStatement categoriesGet, Map> categories, Map catIndexes) throws IOException, SQLException { long l = tree.getNode(); int x = (int) (l >> 31); int y = (int) (l & ((1 << 31) - 1)); boolean end = zoom == ZOOM_TO_SAVE_END; long fp = writer.startWritePoiBox(zoom, x, y, end); + if(zoom >= ZOOM_TO_WRITE_CATEGORIES_START && zoom <= ZOOM_TO_WRITE_CATEGORIES_END){ + categoriesGet.setInt(1, x << (31 - zoom)); + categoriesGet.setInt(2, (x + 1) << (31 - zoom)); + categoriesGet.setInt(3, y << (31 - zoom)); + categoriesGet.setInt(4, (y + 1) << (31 - zoom)); + ResultSet rs = categoriesGet.executeQuery(); + TIntArrayList types = new TIntArrayList(); + while(rs.next()){ + String cat = rs.getString(1); + String subcat = rs.getString(2); + buildTypeIds(cat, subcat, categories, catIndexes, types); + } + writer.writePOICategories(types); + rs.close(); + } + if (!end) { for (Tree subTree : tree.getSubtrees()) { - writePoiBoxes(writer, subTree, zoom + 1, fpToWriteSeeks); + writePoiBoxes(writer, subTree, zoom + 1, fpToWriteSeeks, categoriesGet, categories, catIndexes); } } else { fpToWriteSeeks.put(l, fp); @@ -403,6 +425,9 @@ public class IndexPoiCreator extends AbstractIndexPartCreator { } public static void main(String[] args) throws SQLException, FileNotFoundException, IOException { + // TODO support multiple reading amenity types! + // TODO support string trigramms + // TODO support live results long time = System.currentTimeMillis(); IndexPoiCreator poiCreator = new IndexPoiCreator(); poiCreator.poiConnection = (Connection) DBDialect.SQLITE.getDatabaseConnection( diff --git a/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryBinary.java b/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryBinary.java index a96642a987..b49ef8117a 100644 --- a/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryBinary.java +++ b/OsmAnd/src/net/osmand/plus/AmenityIndexRepositoryBinary.java @@ -1,6 +1,5 @@ package net.osmand.plus; -import gnu.trove.list.array.TIntArrayList; import java.io.IOException; import java.util.ArrayList; @@ -9,14 +8,11 @@ import java.util.List; import net.osmand.Algoritms; import net.osmand.LogUtil; import net.osmand.binary.BinaryMapIndexReader; -import net.osmand.binary.BinaryMapIndexReader.MapIndex; -import net.osmand.binary.BinaryMapIndexReader.SearchFilter; +import net.osmand.binary.BinaryMapIndexReader.SearchPoiTypeFilter; import net.osmand.binary.BinaryMapIndexReader.SearchRequest; -import net.osmand.binary.BinaryMapIndexReader.TagValuePair; import net.osmand.data.Amenity; import net.osmand.data.AmenityType; import net.osmand.osm.LatLon; -import net.osmand.osm.MapRenderingTypes; import net.osmand.osm.MapUtils; import org.apache.commons.logging.Log; @@ -59,25 +55,11 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository { int sbottom = MapUtils.get31TileNumberY(bottomLatitude); int stop = MapUtils.get31TileNumberY(topLatitude); - SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest(sleft, sright, stop, sbottom, 16); - // TODO types and filter and live results - req.setSearchFilter(new SearchFilter(){ - + SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest(sleft, sright, stop, sbottom, limit, 16); + req.setPoiTypeFilter(new SearchPoiTypeFilter(){ @Override - public boolean accept(TIntArrayList types, MapIndex root) { - for (int j = 0; j < types.size(); j++) { - int wholeType = types.get(j); - TagValuePair pair = root.decodeType(wholeType); - if (pair != null) { - AmenityType type = MapRenderingTypes.getAmenityType(pair.tag, pair.value); - if (type != null) { - if(filter.acceptTypeSubtype(type, MapRenderingTypes.getAmenitySubtype(pair.tag, pair.value))){ - return true; - } - } - } - } - return false; + public boolean accept(AmenityType type, String subcategory) { + return filter.acceptTypeSubtype(type, subcategory); } }); try { diff --git a/OsmAnd/src/net/osmand/plus/PoiFilter.java b/OsmAnd/src/net/osmand/plus/PoiFilter.java index 5b4e7b5138..69961fe7fa 100644 --- a/OsmAnd/src/net/osmand/plus/PoiFilter.java +++ b/OsmAnd/src/net/osmand/plus/PoiFilter.java @@ -28,8 +28,7 @@ public class PoiFilter { private final boolean isStandardFilter; private final static int finalZoom = 6; - private final static int initialZoom = 13; - private final static int maxInitialCount = 200; + private final static int initialZoom = 14; private int zoom = initialZoom; private final OsmandApplication application; @@ -105,7 +104,7 @@ public class PoiFilter { public List initializeNewSearch(double lat, double lon, int firstTimeLimit){ zoom = getInitialZoom(); - List amenityList = application.getResourceManager().searchAmenities(this, lat, lon, zoom, maxInitialCount); + List amenityList = application.getResourceManager().searchAmenities(this, lat, lon, zoom, -1); MapUtils.sortListOfMapObject(amenityList, lat, lon); while (amenityList.size() > firstTimeLimit) { amenityList.remove(amenityList.size() - 1); @@ -115,11 +114,7 @@ public class PoiFilter { } public List searchAgain(double lat, double lon){ - int limit = -1; - if(zoom == getInitialZoom()){ - limit = maxInitialCount; - } - List amenityList = application.getResourceManager().searchAmenities(this, lat, lon, zoom, limit); + List amenityList = application.getResourceManager().searchAmenities(this, lat, lon, zoom, -1); MapUtils.sortListOfMapObject(amenityList, lat, lon); return amenityList; }