diff --git a/OsmAnd-java/src/net/osmand/binary/BinaryMapIndexReader.java b/OsmAnd-java/src/net/osmand/binary/BinaryMapIndexReader.java index 35f6b11a7d..8b5f0bbdcc 100644 --- a/OsmAnd-java/src/net/osmand/binary/BinaryMapIndexReader.java +++ b/OsmAnd-java/src/net/osmand/binary/BinaryMapIndexReader.java @@ -26,6 +26,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -397,7 +399,7 @@ public class BinaryMapIndexReader { } return ""; } - + public String getRegionName() { List rg = getRegionNames(); if (rg.size() == 0) { @@ -405,7 +407,24 @@ public class BinaryMapIndexReader { } String ls = rg.get(0); if (ls.lastIndexOf('_') != -1) { - return ls.substring(0, ls.lastIndexOf('_')).replace('_', ' '); + if (ls.matches(".*([0-9]+_*){3}\\.obf")) { + Pattern osmDiffDateEnding = Pattern.compile("_([0-9]+_*){3}\\.obf"); + Matcher m = osmDiffDateEnding.matcher(ls); + if (m.find()) { + ls = ls.substring(0, m.start()); + } + return ls.substring(0, ls.lastIndexOf('_')).replace('_', ' '); + + } else { + if (ls.contains(".")) { + ls = ls.substring(0, ls.indexOf(".")); + } + if (ls.endsWith("_2")) { + ls = ls.substring(0, ls.length() - "_2".length()); + } + return ls.substring(0, ls.lastIndexOf('_')).replace('_', ' '); + } + } return ls; } diff --git a/OsmAnd-java/src/net/osmand/data/Amenity.java b/OsmAnd-java/src/net/osmand/data/Amenity.java index fef60b5866..4bc6df691e 100644 --- a/OsmAnd-java/src/net/osmand/data/Amenity.java +++ b/OsmAnd-java/src/net/osmand/data/Amenity.java @@ -29,6 +29,8 @@ public class Amenity extends MapObject { public static final String OPENING_HOURS = "opening_hours"; public static final String CONTENT = "content"; public static final String CUISINE = "cuisine"; + public static final String OSM_DELETE_VALUE = "delete"; + public static final String OSM_DELETE_TAG = "osmand_change"; private String subType; private PoiCategory type; @@ -307,4 +309,8 @@ public class Amenity extends MapObject { } return x; } + + public boolean isClosed() { + return OSM_DELETE_VALUE.equals(getAdditionalInfo(OSM_DELETE_TAG)); + } } diff --git a/OsmAnd-java/src/net/osmand/search/core/SearchCoreFactory.java b/OsmAnd-java/src/net/osmand/search/core/SearchCoreFactory.java index a6e21fe416..52d004a8d3 100644 --- a/OsmAnd-java/src/net/osmand/search/core/SearchCoreFactory.java +++ b/OsmAnd-java/src/net/osmand/search/core/SearchCoreFactory.java @@ -38,14 +38,18 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeSet; import gnu.trove.list.array.TIntArrayList; +import gnu.trove.set.hash.TLongHashSet; public class SearchCoreFactory { @@ -486,6 +490,7 @@ public class SearchCoreFactory { SearchPhraseDataType.POI); final NameStringMatcher nm = phrase.getNameStringMatcher(); QuadRect bbox = phrase.getRadiusBBoxToSearch(BBOX_RADIUS_INSIDE); + final Set ids = new HashSet(); SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest( (int)bbox.centerX(), (int)bbox.centerY(), phrase.getUnknownSearchWord(), @@ -498,6 +503,10 @@ public class SearchCoreFactory { if (limit ++ > LIMIT) { return false; } + String poiID = object.getType().getKeyName() + "_" + object.getId(); + if (ids.contains(poiID)) { + return false; + } SearchResult sr = new SearchResult(phrase); sr.otherNames = object.getAllNames(true); sr.localeName = object.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate()); @@ -523,6 +532,7 @@ public class SearchCoreFactory { phrase.countUnknownWordsMatch(sr); sr.objectType = ObjectType.POI; resultMatcher.publish(sr); + ids.add(poiID); return false; } @@ -726,8 +736,9 @@ public class SearchCoreFactory { QuadRect bbox = phrase.getRadiusBBoxToSearch(10000); List oo = phrase.getOfflineIndexes(); + Set searchedPois = new TreeSet<>(); for (BinaryMapIndexReader o : oo) { - ResultMatcher rm = getResultMatcher(phrase, resultMatcher, o); + ResultMatcher rm = getResultMatcher(phrase, resultMatcher, o, searchedPois); if (obj instanceof CustomSearchPoiFilter) { rm = ((CustomSearchPoiFilter) obj).wrapResultMatcher(rm); } @@ -743,13 +754,20 @@ public class SearchCoreFactory { } private ResultMatcher getResultMatcher(final SearchPhrase phrase, final SearchResultMatcher resultMatcher, - final BinaryMapIndexReader selected) { + final BinaryMapIndexReader selected, final Set searchedPois) { final NameStringMatcher ns = phrase.getNameStringMatcher(); return new ResultMatcher() { @Override public boolean publish(Amenity object) { SearchResult res = new SearchResult(phrase); + String poiID = object.getType().getKeyName() + "_" + object.getId(); + if(!searchedPois.add(poiID)) { + return false; + } + if(object.isClosed()) { + return false; + } res.localeName = object.getName(phrase.getSettings().getLang(), phrase.getSettings().isTransliterate()); res.otherNames = object.getAllNames(true); if (Algorithms.isEmpty(res.localeName)) { diff --git a/OsmAnd-java/src/net/osmand/search/core/SearchPhrase.java b/OsmAnd-java/src/net/osmand/search/core/SearchPhrase.java index 10327e832a..e0eac2a796 100644 --- a/OsmAnd-java/src/net/osmand/search/core/SearchPhrase.java +++ b/OsmAnd-java/src/net/osmand/search/core/SearchPhrase.java @@ -13,6 +13,7 @@ import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -531,41 +532,74 @@ public class SearchPhrase { } } - public void sortFiles() { - if(indexes == null) { - indexes = new ArrayList<>(getOfflineIndexes()); - } - final LatLon ll = getLastTokenLocation(); - if(ll != null) { - Collections.sort(indexes, new Comparator() { - Map locations = new HashMap<>(); + public void sortFiles() { + if (indexes == null) { + indexes = new ArrayList<>(getOfflineIndexes()); + } + Map> diffsByRegion = getDiffsByRegion(); + final LatLon ll = getLastTokenLocation(); + if (ll != null) { + Collections.sort(indexes, new Comparator() { + Map locations = new HashMap<>(); - @Override - public int compare(BinaryMapIndexReader o1, BinaryMapIndexReader o2) { - LatLon rc1 = o1 == null ? null : getLocation(o1); - LatLon rc2 = o2 == null ? null : getLocation(o2); - double d1 = rc1 == null ? 10000000d : MapUtils.getDistance(rc1, ll); - double d2 = rc2 == null ? 10000000d : MapUtils.getDistance(rc2, ll); - return Double.compare(d1, d2); - } + @Override + public int compare(BinaryMapIndexReader o1, BinaryMapIndexReader o2) { + LatLon rc1 = o1 == null ? null : getLocation(o1); + LatLon rc2 = o2 == null ? null : getLocation(o2); + double d1 = rc1 == null ? 10000000d : MapUtils.getDistance(rc1, ll); + double d2 = rc2 == null ? 10000000d : MapUtils.getDistance(rc2, ll); + return Double.compare(d1, d2); + } + + private LatLon getLocation(BinaryMapIndexReader o1) { + if (locations.containsKey(o1)) { + return locations.get(o1); + } + LatLon rc1 = null; + if (o1.containsMapData()) { + rc1 = o1.getMapIndexes().get(0).getCenterLatLon(); + } else { + rc1 = o1.getRegionCenter(); + } + locations.put(o1, rc1); + return rc1; + } + }); + if (!diffsByRegion.isEmpty()) { + List finalSort = new ArrayList<>(); + for (int i = 0; i < indexes.size(); i++) { + BinaryMapIndexReader currFile = indexes.get(i); + if (diffsByRegion.get(currFile.getRegionName()) != null) { + finalSort.addAll(diffsByRegion.get(currFile.getRegionName())); + finalSort.add(currFile); + } else { + finalSort.add(currFile); + } + } + indexes.clear(); + indexes.addAll(finalSort); + } + } + } + + private Map> getDiffsByRegion() { + Map> result = new HashMap<>(); + Iterator it = indexes.iterator(); + while (it.hasNext()) { + BinaryMapIndexReader r = it.next(); + if (r.getFile().getName().matches(".*([0-9]+_*){3}\\.obf")) { + String currRegionName = r.getRegionName(); + if (result.containsKey(currRegionName)) { + result.get(currRegionName).add(r); + } else { + result.put(currRegionName, new ArrayList<>(Arrays.asList(r))); + } + it.remove(); + } + } + return result; + } - private LatLon getLocation(BinaryMapIndexReader o1) { - if(locations.containsKey(o1)) { - return locations.get(o1); - } - LatLon rc1 = null; - if(o1.containsMapData()) { - rc1 = o1.getMapIndexes().get(0).getCenterLatLon(); - } else { - rc1 = o1.getRegionCenter(); - } - locations.put(o1, rc1); - return rc1; - } - }); - } - } - public static class NameStringMatcher implements StringMatcher { private CollatorStringMatcher sm; diff --git a/OsmAnd-java/src/net/osmand/util/Algorithms.java b/OsmAnd-java/src/net/osmand/util/Algorithms.java index 4d3637bf98..32a01eb452 100644 --- a/OsmAnd-java/src/net/osmand/util/Algorithms.java +++ b/OsmAnd-java/src/net/osmand/util/Algorithms.java @@ -2,6 +2,7 @@ package net.osmand.util; import net.osmand.IProgress; import net.osmand.PlatformUtil; +import net.osmand.binary.BinaryMapIndexReader; import org.apache.commons.logging.Log; @@ -113,29 +114,39 @@ public class Algorithms { return -simplifyFileName(o1.getName()).compareTo(simplifyFileName(o2.getName())); } - public String simplifyFileName(String fn) { - String lc = fn.toLowerCase(); - if (lc.contains(".")) { - lc = lc.substring(0, lc.indexOf(".")); - } - if (lc.endsWith("_2")) { - lc = lc.substring(0, lc.length() - "_2".length()); - } - boolean hasTimestampEnd = false; - for (int i = 0; i < lc.length(); i++) { - if (lc.charAt(i) >= '0' && lc.charAt(i) <= '9') { - hasTimestampEnd = true; - break; - } - } - if (!hasTimestampEnd) { - lc += "_00_00_00"; - } - return lc; - } }; } + private static String simplifyFileName(String fn) { + String lc = fn.toLowerCase(); + if (lc.contains(".")) { + lc = lc.substring(0, lc.indexOf(".")); + } + if (lc.endsWith("_2")) { + lc = lc.substring(0, lc.length() - "_2".length()); + } + boolean hasTimestampEnd = false; + for (int i = 0; i < lc.length(); i++) { + if (lc.charAt(i) >= '0' && lc.charAt(i) <= '9') { + hasTimestampEnd = true; + break; + } + } + if (!hasTimestampEnd) { + lc += "_00_00_00"; + } + return lc; + } + + public static Comparator getStringVersionComparator() { + return new Comparator() { + @Override + public int compare(String o1, String o2) { + return -simplifyFileName(o1).compareTo(simplifyFileName(o2)); + } + }; + } + private static final char CHAR_TOSPLIT = 0x01; public static Map decodeMap(String s) { diff --git a/OsmAnd/src/net/osmand/plus/poi/PoiUIFilter.java b/OsmAnd/src/net/osmand/plus/poi/PoiUIFilter.java index 58b53cb878..5e49704250 100644 --- a/OsmAnd/src/net/osmand/plus/poi/PoiUIFilter.java +++ b/OsmAnd/src/net/osmand/plus/poi/PoiUIFilter.java @@ -421,12 +421,20 @@ public class PoiUIFilter implements SearchPoiTypeFilter, Comparable @Override public ResultMatcher wrapResultMatcher(final ResultMatcher matcher) { final AmenityNameFilter nm = getNameFilter(filterByName); + final Set searchedPois = new TreeSet<>(); return new ResultMatcher() { @Override public boolean publish(Amenity a) { if (nm.accept(a)) { if (matcher == null || matcher.publish(a)) { + String poiID = a.getType().getKeyName() + "_" + a.getId(); + if (!searchedPois.add(poiID)) { + return false; + } + if (a.isClosed()) { + return false; + } return true; } } diff --git a/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java b/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java index 98255722b9..803945c8a7 100644 --- a/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java +++ b/OsmAnd/src/net/osmand/plus/resources/ResourceManager.java @@ -60,6 +60,7 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -715,7 +716,10 @@ public class ResourceManager { int left31 = MapUtils.get31TileNumberX(leftLongitude); int bottom31 = MapUtils.get31TileNumberY(bottomLatitude); int right31 = MapUtils.get31TileNumberX(rightLongitude); - for (AmenityIndexRepository index : amenityRepositories.values()) { + List fileNames = new ArrayList(amenityRepositories.keySet()); + Collections.sort(fileNames, Algorithms.getStringVersionComparator()); + for (String name : fileNames) { + AmenityIndexRepository index = amenityRepositories.get(name); if (matcher != null && matcher.isCancelled()) { searchAmenitiesInProgress = false; break; @@ -734,8 +738,8 @@ public class ResourceManager { } return amenities; } - - public List searchAmenitiesOnThePath(List locations, double radius, SearchPoiTypeFilter filter, + + public List searchAmenitiesOnThePath(List locations, double radius, SearchPoiTypeFilter filter, ResultMatcher matcher) { searchAmenitiesInProgress = true; final List amenities = new ArrayList();