Small improvements
This commit is contained in:
parent
e7d1c174fd
commit
ade397475a
6 changed files with 149 additions and 54 deletions
|
@ -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<Amenity> buildSearchPoiRequest(int sleft, int sright, int stop, int sbottom, int zoom){
|
||||
public static SearchRequest<Amenity> buildSearchPoiRequest(int sleft, int sright, int stop, int sbottom, int limit, int zoom){
|
||||
SearchRequest<Amenity> request = new SearchRequest<Amenity>();
|
||||
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<T> {
|
||||
// 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<T> 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<Amenity> results = reader.searchPoi(buildSearchPoiRequest(sleft, sright, stop, sbottom, 15));
|
||||
SearchRequest<Amenity> 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<Amenity> results = reader.searchPoi(req);
|
||||
for(Amenity a : results){
|
||||
System.out.println(a.getType() + " " + a.getSubType() + " " + a.getName() + " " + a.getLocation());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<String>());
|
||||
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<String> 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());
|
||||
|
@ -294,8 +300,43 @@ public class BinaryMapPoiReaderAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean checkCategories(SearchRequest<Amenity> 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<String> 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<Amenity> req) throws IOException {
|
||||
int px, int py, int pzoom, TIntArrayList offsets, SearchRequest<Amenity> 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;
|
||||
|
||||
|
@ -352,5 +407,4 @@ public class BinaryMapPoiReaderAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Amenity> tempAmenityList = new ArrayList<Amenity>();
|
||||
|
@ -154,7 +156,6 @@ public class IndexPoiCreator extends AbstractIndexPartCreator {
|
|||
|
||||
private void buildTypeIds(String category, String subcategory, Map<String, Map<String, Integer>> categories,
|
||||
Map<String, Integer> catIndexes, TIntArrayList types) {
|
||||
types.clear();
|
||||
Map<String, Integer> 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<Long, Long> fpToWriteSeeks = new LinkedHashMap<Long, Long>();
|
||||
for (Tree<Long> 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<Long> tree, int zoom, Map<Long, Long> fpToWriteSeeks) throws IOException {
|
||||
private void writePoiBoxes(BinaryMapIndexWriter writer, Tree<Long> tree, int zoom, Map<Long, Long> fpToWriteSeeks,
|
||||
PreparedStatement categoriesGet, Map<String, Map<String, Integer>> categories, Map<String, Integer> 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<Long> 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(
|
||||
|
|
|
@ -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<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(sleft, sright, stop, sbottom, 16);
|
||||
// TODO types and filter and live results
|
||||
req.setSearchFilter(new SearchFilter(){
|
||||
|
||||
SearchRequest<Amenity> 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 {
|
||||
|
|
|
@ -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<Amenity> initializeNewSearch(double lat, double lon, int firstTimeLimit){
|
||||
zoom = getInitialZoom();
|
||||
List<Amenity> amenityList = application.getResourceManager().searchAmenities(this, lat, lon, zoom, maxInitialCount);
|
||||
List<Amenity> 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<Amenity> searchAgain(double lat, double lon){
|
||||
int limit = -1;
|
||||
if(zoom == getInitialZoom()){
|
||||
limit = maxInitialCount;
|
||||
}
|
||||
List<Amenity> amenityList = application.getResourceManager().searchAmenities(this, lat, lon, zoom, limit);
|
||||
List<Amenity> amenityList = application.getResourceManager().searchAmenities(this, lat, lon, zoom, -1);
|
||||
MapUtils.sortListOfMapObject(amenityList, lat, lon);
|
||||
return amenityList;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue