Merge remote-tracking branch 'origin/master'

This commit is contained in:
Weblate 2016-07-12 11:33:07 +02:00
commit 092c8289da
5 changed files with 207 additions and 44 deletions

View file

@ -16,6 +16,7 @@ import net.osmand.CollatorStringMatcher.StringMatcherMode;
import net.osmand.PlatformUtil;
import net.osmand.StringMatcher;
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
import net.osmand.binary.BinaryMapPoiReaderAdapter.PoiRegion;
import net.osmand.binary.OsmandOdb.AddressNameIndexDataAtom;
import net.osmand.binary.OsmandOdb.OsmAndAddressIndex.CitiesIndex;
import net.osmand.binary.OsmandOdb.OsmAndAddressNameIndexData;
@ -55,6 +56,10 @@ public class BinaryMapAddressReaderAdapter {
List<CitiesBlock> cities = new ArrayList<BinaryMapAddressReaderAdapter.CitiesBlock>();
LatLon calculatedCenter = null;
public int bottom31;
public int top31;
public int right31;
public int left31;
public String getEnName() {
return enName;
@ -108,12 +113,40 @@ public class BinaryMapAddressReaderAdapter {
private int readInt() throws IOException {
return map.readInt();
}
private void readBoundariesIndex(AddressRegion region) throws IOException {
while (true) {
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
switch (tag) {
case 0:
return;
case OsmandOdb.OsmAndTileBox.LEFT_FIELD_NUMBER:
region.left31 = codedIS.readUInt32();
break;
case OsmandOdb.OsmAndTileBox.RIGHT_FIELD_NUMBER:
region.right31 = codedIS.readUInt32();
break;
case OsmandOdb.OsmAndTileBox.TOP_FIELD_NUMBER:
region.top31 = codedIS.readUInt32();
break;
case OsmandOdb.OsmAndTileBox.BOTTOM_FIELD_NUMBER:
region.bottom31 = codedIS.readUInt32();
break;
default:
skipUnknownField(t);
break;
}
}
}
protected void readAddressIndex(AddressRegion region) throws IOException {
while (true) {
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
int length;
int oldLimit;
switch (tag) {
case 0:
if (region.enName == null || region.enName.length() == 0) {
@ -126,9 +159,16 @@ public class BinaryMapAddressReaderAdapter {
case OsmandOdb.OsmAndAddressIndex.NAME_EN_FIELD_NUMBER:
region.enName = codedIS.readString();
break;
case OsmandOdb.OsmAndAddressIndex.BOUNDARIES_FIELD_NUMBER:
length = codedIS.readRawVarint32();
oldLimit = codedIS.pushLimit(length);
readBoundariesIndex(region);
codedIS.popLimit(oldLimit);
region.enName = codedIS.readString();
break;
case OsmandOdb.OsmAndAddressIndex.ATTRIBUTETAGSTABLE_FIELD_NUMBER:
int length2 = codedIS.readRawVarint32();
int oldLimit = codedIS.pushLimit(length2);
length = codedIS.readRawVarint32();
oldLimit = codedIS.pushLimit(length);
region.attributeTagsTable = map.readStringTable();
codedIS.popLimit(oldLimit);
break;
@ -156,7 +196,7 @@ public class BinaryMapAddressReaderAdapter {
break;
case OsmandOdb.OsmAndAddressIndex.NAMEINDEX_FIELD_NUMBER:
region.indexNameOffset = codedIS.getTotalBytesRead();
int length = readInt();
length = readInt();
codedIS.seek(region.indexNameOffset + length + 4);
break;
default:

View file

@ -340,6 +340,24 @@ public class BinaryMapIndexReader {
}
return false;
}
public boolean containsPoiData(int left31x, int top31y, int right31x, int bottom31y) {
for (PoiRegion index : poiIndexes) {
if (right31x >= index.left31 && left31x <= index.right31 && index.top31 <= bottom31y && index.bottom31 >= top31y) {
return true;
}
}
return false;
}
public boolean containsAddressData(int left31x, int top31y, int right31x, int bottom31y) {
for (AddressRegion index : addressIndexes) {
if (right31x >= index.left31 && left31x <= index.right31 && index.top31 <= bottom31y && index.bottom31 >= top31y) {
return true;
}
}
return false;
}
public boolean containsMapData(int tile31x, int tile31y, int zoom) {
for (MapIndex mapIndex : mapIndexes) {

View file

@ -59,6 +59,10 @@ public class BinaryMapPoiReaderAdapter {
double rightLongitude;
double topLatitude;
double bottomLatitude;
int left31;
int right31;
int top31;
int bottom31;
public double getLeftLongitude() {
return leftLongitude;
@ -134,16 +138,20 @@ public class BinaryMapPoiReaderAdapter {
case 0:
return;
case OsmandOdb.OsmAndTileBox.LEFT_FIELD_NUMBER:
region.leftLongitude = MapUtils.get31LongitudeX(codedIS.readUInt32());
region.left31 = codedIS.readUInt32();
region.leftLongitude = MapUtils.get31LongitudeX(region.left31);
break;
case OsmandOdb.OsmAndTileBox.RIGHT_FIELD_NUMBER:
region.rightLongitude = MapUtils.get31LongitudeX(codedIS.readUInt32());
region.right31 = codedIS.readUInt32();
region.rightLongitude = MapUtils.get31LongitudeX(region.right31);
break;
case OsmandOdb.OsmAndTileBox.TOP_FIELD_NUMBER:
region.topLatitude = MapUtils.get31LatitudeY(codedIS.readUInt32());
region.top31 = codedIS.readUInt32();
region.topLatitude = MapUtils.get31LatitudeY(region.top31);
break;
case OsmandOdb.OsmAndTileBox.BOTTOM_FIELD_NUMBER:
region.bottomLatitude = MapUtils.get31LatitudeY(codedIS.readUInt32());
region.bottom31 = codedIS.readUInt32();
region.bottomLatitude = MapUtils.get31LatitudeY(region.bottom31);
break;
default:
skipUnknownField(t);

View file

@ -1,9 +1,11 @@
package net.osmand.search.example.core;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@ -13,6 +15,7 @@ import net.osmand.CollatorStringMatcher.StringMatcherMode;
import net.osmand.OsmAndCollator;
import net.osmand.ResultMatcher;
import net.osmand.StringMatcher;
import net.osmand.binary.BinaryMapAddressReaderAdapter;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.binary.BinaryMapIndexReader.SearchPoiTypeFilter;
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
@ -31,30 +34,32 @@ import net.osmand.osm.PoiFilter;
import net.osmand.osm.PoiType;
import net.osmand.search.example.SearchUICore.SearchResultMatcher;
import net.osmand.search.example.core.SearchPhrase.NameStringMatcher;
import net.osmand.search.example.core.SearchPhrase.SearchPhraseDataType;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
public class SearchCoreFactory {
// TODO fix search amenity by type (category/additional)
// TODO streets by city
// TODO display closest city to villages
// TODO search only closest file (global bbox)
// TODO limit to one file if city/street/village/poi selected
// TODO fix search amenity by type (category/additional)
// TODO streets by city
// TODO amenity by name
// TODO add location parse
// TODO add url parse (geo)
// TODO amenity by name
// TODO display closest city to villages (and city to street)
// TODO automatically increase radius if nothing found
// TODO buildings interpolation
// TODO show buildings if street is one or default ( <CITY>, CITY (den ilp), 1186RM)
// TODO exclude duplicate streets/cities...
// TODO display results momentarily
// TODO add full text search with comma
// TODO add full text search without comma
// TODO MED display results momentarily
// TODO MED add full text search with comma
// TODO MED add full text search without comma
// TODO LOW automatically increase radius if nothing found
public static abstract class SearchBaseAPI implements SearchCoreAPI {
@ -63,20 +68,8 @@ public class SearchCoreFactory {
return true;
}
public QuadRect getBBoxToSearch(int radiusInMeters, int radiusLevel, LatLon loc) {
if(loc == null) {
return null;
}
float calcRadios = radiusLevel * radiusInMeters;
float coeff = (float) (calcRadios / MapUtils.getTileDistanceWidth(SearchRequest.ZOOM_TO_SEARCH_POI));
double tx = MapUtils.getTileNumberX(SearchRequest.ZOOM_TO_SEARCH_POI, loc.getLongitude());
double ty = MapUtils.getTileNumberY(SearchRequest.ZOOM_TO_SEARCH_POI, loc.getLatitude());
double topLeftX = tx - coeff;
double topLeftY = ty - coeff;
double bottomRightX = tx + coeff;
double bottomRightY = ty + coeff;
double pw = MapUtils.getPowZoom(31 - SearchRequest.ZOOM_TO_SEARCH_POI);
return new QuadRect(topLeftX * pw, topLeftY * pw, bottomRightX * pw, bottomRightY * pw);
public QuadRect getBBoxToSearch(SearchPhrase phrase, int radiusInMeters) {
return phrase.getBBoxToSearch(phrase.getRadiusLevel() * radiusInMeters);
}
@Override
@ -125,6 +118,7 @@ public class SearchCoreFactory {
private static final int DEFAULT_BBOX_RADIUS = 1000*1000;
private static final int LIMIT = 10000;
private Map<BinaryMapIndexReader, List<City>> townCities = new LinkedHashMap<>();
public boolean isLastWordPoi(SearchPhrase p) {
return p.isLastWord(ObjectType.POI);
@ -150,14 +144,10 @@ public class SearchCoreFactory {
// int letters = phrase.getLastWord().length() / 3 + 1;
final boolean locSpecified = phrase.getLastTokenLocation() != null;
LatLon loc = phrase.getLastTokenLocation();
final QuadRect streetBbox = getBBoxToSearch(DEFAULT_BBOX_RADIUS, phrase.getRadiusLevel(),
phrase.getLastTokenLocation());
final QuadRect postcodeBbox = getBBoxToSearch(DEFAULT_BBOX_RADIUS * 5, phrase.getRadiusLevel(),
phrase.getLastTokenLocation());
final QuadRect villagesBbox = getBBoxToSearch(DEFAULT_BBOX_RADIUS * 5, phrase.getRadiusLevel(),
phrase.getLastTokenLocation());
final QuadRect cityBbox = getBBoxToSearch(DEFAULT_BBOX_RADIUS * 10, phrase.getRadiusLevel(),
phrase.getLastTokenLocation());
final QuadRect streetBbox = getBBoxToSearch(phrase, DEFAULT_BBOX_RADIUS);
final QuadRect postcodeBbox = getBBoxToSearch(phrase, DEFAULT_BBOX_RADIUS * 5);
final QuadRect villagesBbox = getBBoxToSearch(phrase, DEFAULT_BBOX_RADIUS * 5);
final QuadRect cityBbox = getBBoxToSearch(phrase, DEFAULT_BBOX_RADIUS * 10);
final int priority = isNoSelectedType(phrase) ? 1 : 3;
final BinaryMapIndexReader[] currentFile = new BinaryMapIndexReader[1];
ResultMatcher<MapObject> rm = new ResultMatcher<MapObject>() {
@ -217,6 +207,16 @@ public class SearchCoreFactory {
resultMatcher.isCancelled();
}
};
Iterator<BinaryMapIndexReader> offlineIndexes = phrase.getOfflineIndexes(DEFAULT_BBOX_RADIUS * 10, SearchPhraseDataType.ADDRESS);
while(offlineIndexes.hasNext()) {
BinaryMapIndexReader r = offlineIndexes.next();
if(!townCities.containsKey(r)) {
BinaryMapIndexReader.buildAddressRequest(null);
List<City> l = r.getCities(null, BinaryMapAddressReaderAdapter.CITY_TOWN_TYPE);
townCities.put(r, l);
}
}
for(BinaryMapIndexReader r : phrase.getOfflineIndexes()) {
currentFile[0] = r;
SearchRequest<MapObject> req = BinaryMapIndexReader.buildAddressByNameRequest(rm,
@ -328,11 +328,13 @@ public class SearchCoreFactory {
public boolean search(final SearchPhrase phrase, final SearchResultMatcher resultMatcher) throws IOException {
if(phrase.isLastWord(ObjectType.POI_TYPE)) {
final AbstractPoiType pt = (AbstractPoiType) phrase.getLastSelectedWord().getResult().object;
QuadRect bbox = getBBoxToSearch(10000, phrase.getRadiusLevel(), phrase.getLastTokenLocation());
QuadRect bbox = getBBoxToSearch(phrase, 10000);
List<BinaryMapIndexReader> oo = phrase.getOfflineIndexes();
final BinaryMapIndexReader[] selected = new BinaryMapIndexReader[1];
final NameStringMatcher ns = phrase.getNameStringMatcher();
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest((int)bbox.left, (int)bbox.right, (int)bbox.top, (int)bbox.bottom, -1,
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
(int)bbox.left, (int)bbox.right,
(int)bbox.top, (int)bbox.bottom, -1,
new SearchPoiTypeFilter() {
@Override
@ -384,10 +386,9 @@ public class SearchCoreFactory {
return resultMatcher.isCancelled();
}
});
for(BinaryMapIndexReader o : oo) {
for (BinaryMapIndexReader o : oo) {
selected[0] = o;
o.searchPoi(req);
o.searchPoi(req);
}
}
return true;

View file

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@ -11,7 +12,9 @@ import net.osmand.CollatorStringMatcher;
import net.osmand.StringMatcher;
import net.osmand.CollatorStringMatcher.StringMatcherMode;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
import net.osmand.data.LatLon;
import net.osmand.data.QuadRect;
import net.osmand.util.MapUtils;
//immutable object
@ -23,6 +26,12 @@ public class SearchPhrase {
private SearchSettings settings;
private List<BinaryMapIndexReader> indexes;
private String lastWordTrim;
private QuadRect cache1kmRect;
public enum SearchPhraseDataType {
MAP, ADDRESS, ROUTING, POI
}
public SearchPhrase(SearchSettings settings) {
this.settings = settings;
@ -72,6 +81,93 @@ public class SearchPhrase {
return words;
}
public QuadRect getBBoxToSearch(int radiusInMeters) {
QuadRect cache1kmRect = get1km31Rect();
if(cache1kmRect == null) {
return null;
}
int max = (1 << 31) - 1;
double dx = (cache1kmRect.width() / 2) * radiusInMeters / 1000;
double dy = (cache1kmRect.height() / 2) * radiusInMeters / 1000;
double topLeftX = Math.max(0, cache1kmRect.left - dx);
double topLeftY = Math.max(0, cache1kmRect.top - dy);
double bottomRightX = Math.min(max, cache1kmRect.right + dx);
double bottomRightY = Math.min(max, cache1kmRect.bottom + dy);
return new QuadRect(topLeftX, topLeftY, bottomRightX, bottomRightY);
}
public QuadRect get1km31Rect() {
if(cache1kmRect != null) {
return cache1kmRect;
}
LatLon l = getLastTokenLocation();
if (l == null) {
return null;
}
float coeff = (float) (1000 / MapUtils.getTileDistanceWidth(SearchRequest.ZOOM_TO_SEARCH_POI));
double tx = MapUtils.getTileNumberX(SearchRequest.ZOOM_TO_SEARCH_POI, l.getLongitude());
double ty = MapUtils.getTileNumberY(SearchRequest.ZOOM_TO_SEARCH_POI, l.getLatitude());
double topLeftX = Math.max(0, tx - coeff);
double topLeftY = Math.max(0, ty - coeff);
int max = (1 << SearchRequest.ZOOM_TO_SEARCH_POI) - 1;
double bottomRightX = Math.min(max, tx + coeff);
double bottomRightY = Math.min(max, ty + coeff);
double pw = MapUtils.getPowZoom(31 - SearchRequest.ZOOM_TO_SEARCH_POI);
cache1kmRect = new QuadRect(topLeftX * pw, topLeftY * pw, bottomRightX * pw, bottomRightY * pw);
return cache1kmRect;
}
public Iterator<BinaryMapIndexReader> getOfflineIndexes(int meters, final SearchPhraseDataType dt) {
List<BinaryMapIndexReader> list = indexes != null ? indexes : settings.getOfflineIndexes();
final Iterator<BinaryMapIndexReader> lit = list.iterator();
final QuadRect rect = meters > 0 ? getBBoxToSearch(meters) : null;
return new Iterator<BinaryMapIndexReader>() {
BinaryMapIndexReader next = null;
@Override
public boolean hasNext() {
while (lit.hasNext()) {
next = lit.next();
if(rect != null) {
if(dt == SearchPhraseDataType.POI) {
if(next.containsPoiData((int)rect.left, (int)rect.right, (int)rect.top, (int)rect.bottom)) {
return true;
}
} else if(dt == SearchPhraseDataType.ADDRESS) {
if(next.containsAddressData((int)rect.left, (int)rect.right, (int)rect.top, (int)rect.bottom)) {
return true;
}
} else if(dt == SearchPhraseDataType.ROUTING) {
if(next.containsRouteData((int)rect.left, (int)rect.right, (int)rect.top, (int)rect.bottom, 15)) {
return true;
}
} else {
if(next.containsMapData((int)rect.left, (int)rect.right, (int)rect.top, (int)rect.bottom, 15)) {
return true;
}
}
} else {
return true;
}
}
return false;
}
@Override
public BinaryMapIndexReader next() {
return next;
}
@Override
public void remove() {
}
};
}
public List<BinaryMapIndexReader> getOfflineIndexes() {
if(indexes != null) {
return indexes;