diff --git a/OsmAnd-java/src/net/osmand/data/City.java b/OsmAnd-java/src/net/osmand/data/City.java index a1c113685b..4319cfc93e 100644 --- a/OsmAnd-java/src/net/osmand/data/City.java +++ b/OsmAnd-java/src/net/osmand/data/City.java @@ -45,6 +45,7 @@ public class City extends MapObject { private Map streets = new TreeMap(OsmAndCollator.primaryCollator()); private String isin = null; private String postcode = null; + private City closestCity = null; private static long POSTCODE_INTERNAL_ID = -1000; public static City createPostcode(String postcode){ @@ -92,6 +93,14 @@ public class City extends MapObject { public void setPostcode(String postcode) { this.postcode = postcode; } + + public City getClosestCity() { + return closestCity; + } + + public void setClosestCity(City closestCity) { + this.closestCity = closestCity; + } protected Street registerStreet(Street street, boolean en) { String name = en ? street.getEnName() : street.getName(); diff --git a/OsmAnd-java/src/net/osmand/data/QuadTree.java b/OsmAnd-java/src/net/osmand/data/QuadTree.java index e9bd2f1a99..2b8f0db066 100644 --- a/OsmAnd-java/src/net/osmand/data/QuadTree.java +++ b/OsmAnd-java/src/net/osmand/data/QuadTree.java @@ -35,6 +35,23 @@ public class QuadTree { doInsertData(data, box, root, depth); } + public void clear() { + clear(root); + } + + private void clear(Node rt) { + if(rt != null ){ + if(rt.data != null) { + rt.data.clear(); + } + if(rt.children != null) { + for(Node c : rt.children) { + clear(c); + } + } + } + } + public void insert(T data, float x, float y) { insert(data, new QuadRect(x, y, x, y)); } diff --git a/OsmAnd/assets/bundled_assets.xml b/OsmAnd/assets/bundled_assets.xml index c89015356b..a6d46d9d50 100755 --- a/OsmAnd/assets/bundled_assets.xml +++ b/OsmAnd/assets/bundled_assets.xml @@ -12,6 +12,7 @@ + @@ -34,21 +35,21 @@ + - + - + --> diff --git a/OsmAnd/src/net/osmand/plus/activities/search/SearchCityByNameActivity.java b/OsmAnd/src/net/osmand/plus/activities/search/SearchCityByNameActivity.java index f041a952ce..3320451fce 100644 --- a/OsmAnd/src/net/osmand/plus/activities/search/SearchCityByNameActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/search/SearchCityByNameActivity.java @@ -146,13 +146,20 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity @Override public String getText(City obj) { LatLon l = obj.getLocation(); - if (getFilter().length() > 2 && locationToSearch != null && l != null) { + if (getCurrentFilter().length() > 2 ) { String name = obj.getName(region.useEnglishNames()); if (obj.getType() != null) { name += " [" + OsmAndFormatter.toPublicString(obj.getType(), getMyApplication()) + "]"; } - return name + " - " + //$NON-NLS-1$ - OsmAndFormatter.getFormattedDistance((int) MapUtils.getDistance(l, locationToSearch), getMyApplication()); + if(obj.getClosestCity() != null) { + name += " - " + obj.getClosestCity().getName(region.useEnglishNames()) ; + LatLon loc = obj.getClosestCity().getLocation(); + if(loc != null && l != null) { + name += " " + OsmAndFormatter.getFormattedDistance((int) MapUtils.getDistance(l, loc), getMyApplication()); + } + return name; + } + return name; } else { return obj.getName(region.useEnglishNames()); } diff --git a/OsmAnd/src/net/osmand/plus/resources/RegionAddressRepositoryBinary.java b/OsmAnd/src/net/osmand/plus/resources/RegionAddressRepositoryBinary.java index 23d75f0077..ac24a06230 100644 --- a/OsmAnd/src/net/osmand/plus/resources/RegionAddressRepositoryBinary.java +++ b/OsmAnd/src/net/osmand/plus/resources/RegionAddressRepositoryBinary.java @@ -22,7 +22,10 @@ import net.osmand.data.Building; import net.osmand.data.City; import net.osmand.data.LatLon; import net.osmand.data.MapObject; +import net.osmand.data.QuadRect; +import net.osmand.data.QuadTree; import net.osmand.data.Street; +import net.osmand.util.MapUtils; import org.apache.commons.logging.Log; @@ -34,6 +37,9 @@ public class RegionAddressRepositoryBinary implements RegionAddressRepository { private final LinkedHashMap cities = new LinkedHashMap(); + private int ZOOM_QTREE = 10; + private QuadTree citiesQtree = new QuadTree(new QuadRect(0, 0, 1 << (ZOOM_QTREE + 1), + 1 << (ZOOM_QTREE + 1)), 8, 0.55f); private final Map postCodes; private boolean useEnglishNames = false; private final Collator collator; @@ -59,12 +65,45 @@ public class RegionAddressRepositoryBinary implements RegionAddressRepository { BinaryMapAddressReaderAdapter.CITY_TOWN_TYPE); for (City c : cs) { cities.put(c.getId(), c); + LatLon loc = c.getLocation(); + if(loc != null) { + int y31 = MapUtils.get31TileNumberY(loc.getLatitude()); + int x31 = MapUtils.get31TileNumberX(loc.getLongitude()); + int dz = (31 - ZOOM_QTREE); + citiesQtree.insert(c, new QuadRect((x31 >> dz) - 1, (y31 >> dz) - 1, (x31 >> dz) + 1, (y31 >> dz) + 1)); + } } } catch (IOException e) { log.error("Disk operation failed", e); //$NON-NLS-1$ } } } + + public City getClosestCity(LatLon l, List cache) { + City closest = null; + if (l != null) { + int y31 = MapUtils.get31TileNumberY(l.getLatitude()); + int x31 = MapUtils.get31TileNumberX(l.getLongitude()); + int dz = (31 - ZOOM_QTREE); + if (cache == null) { + cache = new ArrayList(); + } + cache.clear(); + citiesQtree.queryInBox(new QuadRect((x31 >> dz) - 1, (y31 >> dz) - 1, (x31 >> dz) + 1, (y31 >> dz) + 1), + cache); + int min = -1; + + for (City c : cache) { + double d = MapUtils.getDistance(l, c.getLocation()); + if (min == -1 || d < min) { + min = (int) d; + closest = c; + } + } + } + return closest; + + } @Override public synchronized void preloadBuildings(Street street, ResultMatcher resultMatcher) { @@ -119,7 +158,7 @@ public class RegionAddressRepositoryBinary implements RegionAddressRepository { @Override - public List fillWithSuggestedCities(String name, ResultMatcher resultMatcher, boolean searchVillages, LatLon currentLocation) { + public List fillWithSuggestedCities(String name, final ResultMatcher resultMatcher, boolean searchVillages, LatLon currentLocation) { List citiesToFill = new ArrayList(); if (cities.isEmpty()) { preloadCities(resultMatcher); @@ -163,9 +202,26 @@ public class RegionAddressRepositoryBinary implements RegionAddressRepository { int initialsize = citiesToFill.size(); if (/*name.length() >= 3 && */searchVillages) { - List foundCities = file.getCities(region, BinaryMapIndexReader.buildAddressRequest(resultMatcher), + + List foundCities = file.getCities(region, BinaryMapIndexReader.buildAddressRequest(new ResultMatcher() { + List cache = new ArrayList(); + @Override + public boolean publish(City c) { + if(c.getLocation() != null) { + City ct = getClosestCity(c.getLocation(), cache); + c.setClosestCity(ct); + } + return resultMatcher.publish(c); + } + + @Override + public boolean isCancelled() { + return resultMatcher.isCancelled(); + } + }), new CollatorStringMatcher(name,StringMatcherMode.CHECK_STARTS_FROM_SPACE), useEnglishNames, BinaryMapAddressReaderAdapter.VILLAGES_TYPE); + for (City c : foundCities) { citiesToFill.add(c); if (resultMatcher.isCancelled()) { @@ -281,6 +337,7 @@ public class RegionAddressRepositoryBinary implements RegionAddressRepository { @Override public void clearCache() { cities.clear(); + citiesQtree.clear(); postCodes.clear(); }