Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
91b2faef41
14 changed files with 427 additions and 91 deletions
|
@ -1,31 +1,48 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
|
||||
import gnu.trove.iterator.TIntIterator;
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import gnu.trove.map.TIntObjectMap;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
import gnu.trove.set.hash.TIntHashSet;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import net.osmand.Collator;
|
||||
import net.osmand.CollatorStringMatcher;
|
||||
import net.osmand.CollatorStringMatcher.StringMatcherMode;
|
||||
import net.osmand.Location;
|
||||
import net.osmand.OsmAndCollator;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.ResultMatcher;
|
||||
import net.osmand.StringMatcher;
|
||||
import net.osmand.binary.BinaryMapAddressReaderAdapter.AddressRegion;
|
||||
import net.osmand.binary.BinaryMapAddressReaderAdapter.CitiesBlock;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchPoiTypeFilter;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||
import net.osmand.binary.BinaryMapPoiReaderAdapter.PoiRegion;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion;
|
||||
|
@ -43,10 +60,16 @@ import net.osmand.data.MapObject;
|
|||
import net.osmand.data.Street;
|
||||
import net.osmand.data.TransportRoute;
|
||||
import net.osmand.data.TransportStop;
|
||||
import net.osmand.osm.edit.Way;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.google.protobuf.CodedInputStream;
|
||||
import com.google.protobuf.WireFormat;
|
||||
|
@ -1317,6 +1340,8 @@ public class BinaryMapIndexReader {
|
|||
return buildSearchRequest(sleft, sright, stop, sbottom, zoom, searchFilter, null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static SearchRequest<BinaryMapDataObject> buildSearchRequest(int sleft, int sright, int stop, int sbottom, int zoom, SearchFilter searchFilter,
|
||||
ResultMatcher<BinaryMapDataObject> resultMatcher){
|
||||
SearchRequest<BinaryMapDataObject> request = new SearchRequest<BinaryMapDataObject>();
|
||||
|
@ -1345,6 +1370,55 @@ public class BinaryMapIndexReader {
|
|||
return request;
|
||||
}
|
||||
|
||||
public static SearchRequest<Amenity> buildSearchPoiRequest(List<Location> route, double radius,
|
||||
SearchPoiTypeFilter poiTypeFilter, ResultMatcher<Amenity> resultMatcher) {
|
||||
SearchRequest<Amenity> request = new SearchRequest<Amenity>();
|
||||
float coeff = (float) (radius / MapUtils.getTileDistanceWidth(SearchRequest.ZOOM_TO_SEARCH_POI));
|
||||
TIntObjectHashMap<List<Location>> zooms = new TIntObjectHashMap<List<Location>>();
|
||||
for(int i = 1; i < route.size(); i++) {
|
||||
Location cr = route.get(i);
|
||||
Location pr = route.get(i - 1);
|
||||
double tx = MapUtils.getTileNumberX(SearchRequest.ZOOM_TO_SEARCH_POI, cr.getLongitude());
|
||||
double ty = MapUtils.getTileNumberY(SearchRequest.ZOOM_TO_SEARCH_POI, cr.getLatitude());
|
||||
double px = MapUtils.getTileNumberX(SearchRequest.ZOOM_TO_SEARCH_POI, pr.getLongitude());
|
||||
double py = MapUtils.getTileNumberY(SearchRequest.ZOOM_TO_SEARCH_POI, pr.getLatitude());
|
||||
double topLeftX = Math.min(tx, px) - coeff;
|
||||
double topLeftY = Math.min(ty, py) - coeff;
|
||||
double bottomRightX = Math.max(tx, px) + coeff;
|
||||
double bottomRightY = Math.max(ty, py) + coeff;
|
||||
for(int x = (int) topLeftX; x <= bottomRightX; x++) {
|
||||
for(int y = (int) topLeftY; y <= bottomRightY; y++) {
|
||||
int hash = (x << SearchRequest.ZOOM_TO_SEARCH_POI) + y;
|
||||
if(!zooms.containsKey(hash)) {
|
||||
zooms.put(hash, new LinkedList<Location>());
|
||||
}
|
||||
List<Location> ll = zooms.get(hash);
|
||||
ll.add(pr);
|
||||
ll.add(cr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
int sleft = 0, sright = Integer.MAX_VALUE, stop = 0, sbottom = Integer.MAX_VALUE;
|
||||
for(int vl : zooms.keys()) {
|
||||
int x = (vl >> SearchRequest.ZOOM_TO_SEARCH_POI) << (31 - SearchRequest.ZOOM_TO_SEARCH_POI);
|
||||
int y = (vl & ((1 << SearchRequest.ZOOM_TO_SEARCH_POI) -1)) << (31 - SearchRequest.ZOOM_TO_SEARCH_POI);
|
||||
sleft = Math.min(x, sleft);
|
||||
stop = Math.min(y, stop);
|
||||
sbottom = Math.max(y, sbottom);
|
||||
sright = Math.max(x, sright);
|
||||
}
|
||||
request.radius = radius;
|
||||
request.left = sleft;
|
||||
request.zoom = -1;
|
||||
request.right = sright;
|
||||
request.top = stop;
|
||||
request.bottom = sbottom;
|
||||
request.tiles = zooms;
|
||||
request.poiTypeFilter = poiTypeFilter;
|
||||
request.resultMatcher = resultMatcher;
|
||||
return request;
|
||||
}
|
||||
|
||||
public static SearchRequest<Amenity> buildSearchPoiRequest(int sleft, int sright, int stop, int sbottom, int zoom,
|
||||
SearchPoiTypeFilter poiTypeFilter, ResultMatcher<Amenity> matcher){
|
||||
|
@ -1426,6 +1500,7 @@ public class BinaryMapIndexReader {
|
|||
}
|
||||
|
||||
public static class SearchRequest<T> {
|
||||
public final static int ZOOM_TO_SEARCH_POI = 16;
|
||||
private List<T> searchResults = new ArrayList<T>();
|
||||
private boolean land = false;
|
||||
private boolean ocean = false;
|
||||
|
@ -1443,6 +1518,11 @@ public class BinaryMapIndexReader {
|
|||
|
||||
int zoom = 15;
|
||||
int limit = -1;
|
||||
|
||||
// search on the path
|
||||
// stores tile of 16 index and pairs (even length always) of points intersecting tile
|
||||
TIntObjectHashMap<List<Location>> tiles = null;
|
||||
double radius = -1;
|
||||
|
||||
|
||||
String nameQuery = null;
|
||||
|
@ -1469,6 +1549,12 @@ public class BinaryMapIndexReader {
|
|||
protected SearchRequest(){
|
||||
}
|
||||
|
||||
public int getTileHashOnPath(double lat, double lon) {
|
||||
int x = (int) MapUtils.getTileNumberX(SearchRequest.ZOOM_TO_SEARCH_POI, lon);
|
||||
int y = (int) MapUtils.getTileNumberY(SearchRequest.ZOOM_TO_SEARCH_POI, lat);
|
||||
return (x << SearchRequest.ZOOM_TO_SEARCH_POI) | y;
|
||||
}
|
||||
|
||||
|
||||
public boolean publish(T obj){
|
||||
if(resultMatcher == null || resultMatcher.publish(obj)){
|
||||
|
@ -1769,7 +1855,7 @@ public class BinaryMapIndexReader {
|
|||
}
|
||||
|
||||
|
||||
private static boolean testMapSearch = true;
|
||||
private static boolean testMapSearch = false;
|
||||
private static boolean testAddressSearch = false;
|
||||
private static boolean testPoiSearch = false;
|
||||
private static boolean testTransportSearch = false;
|
||||
|
@ -1805,17 +1891,120 @@ public class BinaryMapIndexReader {
|
|||
PoiRegion poiRegion = reader.getPoiIndexes().get(0);
|
||||
testPoiSearch(reader, poiRegion);
|
||||
testPoiSearchByName(reader);
|
||||
testSearchOnthePath(reader);
|
||||
}
|
||||
|
||||
println("MEMORY " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())); //$NON-NLS-1$
|
||||
println("Time " + (System.currentTimeMillis() - time)); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private static void testSearchOnthePath(BinaryMapIndexReader reader) throws IOException {
|
||||
float radius = 1000;
|
||||
long now = System.currentTimeMillis();
|
||||
println("Searching poi on the path...");
|
||||
final List<Location> locations = readGPX(new File(
|
||||
""));
|
||||
SearchRequest<Amenity> req = buildSearchPoiRequest(locations, radius, new SearchPoiTypeFilter() {
|
||||
@Override
|
||||
public boolean accept(AmenityType type, String subcategory) {
|
||||
if (type == AmenityType.SHOP && subcategory.contains("super")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}, null);
|
||||
req.zoom = -1;
|
||||
List<Amenity> results = reader.searchPoi(req);
|
||||
int k = 0;
|
||||
println("Search done in " + (System.currentTimeMillis() - now) + " ms ");
|
||||
now = System.currentTimeMillis();
|
||||
|
||||
for (Amenity a : results) {
|
||||
final float dds = dist(a.getLocation(), locations);
|
||||
if (dds <= radius) {
|
||||
println("+ " + a.getType() + " " + a.getSubType() + " Dist " + dds + " (=" + (float)a.getDeviateDistance() + ") " + a.getName() + " " + a.getLocation());
|
||||
k++;
|
||||
} else {
|
||||
println(a.getType() + " " + a.getSubType() + " Dist " + dds + " " + a.getName() + " " + a.getLocation());
|
||||
}
|
||||
}
|
||||
println("Filtered in " + (System.currentTimeMillis() - now) + "ms " + k + " of " + results.size());
|
||||
}
|
||||
|
||||
private static float dist(LatLon l, List<Location> locations) {
|
||||
float dist = Float.POSITIVE_INFINITY;
|
||||
for(int i = 1; i < locations.size(); i++){
|
||||
dist = Math.min(dist,(float) MapUtils.getOrthogonalDistance(l.getLatitude(), l.getLongitude(),
|
||||
locations.get(i-1).getLatitude(), locations.get(i-1).getLongitude(),
|
||||
locations.get(i).getLatitude(), locations.get(i).getLongitude()));
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
private static Reader getUTF8Reader(InputStream f) throws IOException {
|
||||
BufferedInputStream bis = new BufferedInputStream(f);
|
||||
assert bis.markSupported();
|
||||
bis.mark(3);
|
||||
boolean reset = true;
|
||||
byte[] t = new byte[3];
|
||||
bis.read(t);
|
||||
if (t[0] == ((byte) 0xef) && t[1] == ((byte) 0xbb) && t[2] == ((byte) 0xbf)) {
|
||||
reset = false;
|
||||
}
|
||||
if (reset) {
|
||||
bis.reset();
|
||||
}
|
||||
return new InputStreamReader(bis, "UTF-8");
|
||||
}
|
||||
|
||||
private static List<Location> readGPX(File f) {
|
||||
List<Location> res = new ArrayList<Location>();
|
||||
try {
|
||||
StringBuilder content = new StringBuilder();
|
||||
BufferedReader reader = new BufferedReader(getUTF8Reader(new FileInputStream(f)));
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder dom = factory.newDocumentBuilder();
|
||||
// {
|
||||
// String s = null;
|
||||
// boolean fist = true;
|
||||
// while ((s = reader.readLine()) != null) {
|
||||
// if (fist) {
|
||||
// fist = false;
|
||||
// }
|
||||
// content.append(s).append("\n");
|
||||
// }
|
||||
// }
|
||||
// Document doc = dom.parse(new InputSource(new StringReader(content.toString())));
|
||||
Document doc = dom.parse(new InputSource(reader));
|
||||
NodeList list = doc.getElementsByTagName("trkpt");
|
||||
Way w = new Way(-1);
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
Element item = (Element) list.item(i);
|
||||
try {
|
||||
double lon = Double.parseDouble(item.getAttribute("lon"));
|
||||
double lat = Double.parseDouble(item.getAttribute("lat"));
|
||||
final Location o = new Location("");
|
||||
o.setLatitude(lat);
|
||||
o.setLongitude(lon);
|
||||
res.add(o);
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (SAXException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static void testPoiSearchByName(BinaryMapIndexReader reader) throws IOException {
|
||||
println("Searching by name...");
|
||||
int tileZ = 31 - 14;
|
||||
SearchRequest<Amenity> req = buildSearchPoiRequest(sleft/2+sright/2, stop/2+sbottom/2, "kol",
|
||||
sleft - 1<<tileZ, sleft + 1<<tileZ, stop - 1<<tileZ, stop + 1<<tileZ, null);
|
||||
SearchRequest<Amenity> req = buildSearchPoiRequest(0, 0, "roch",
|
||||
0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, null);
|
||||
reader.searchPoiByName(req);
|
||||
for (Amenity a : req.getSearchResults()) {
|
||||
println(a.getType() + " " + a.getSubType() + " " + a.getName() + " " + a.getLocation());
|
||||
|
@ -2107,5 +2296,7 @@ public class BinaryMapIndexReader {
|
|||
routeAdapter.initRouteRegion(routeReg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -15,11 +15,13 @@ import java.util.List;
|
|||
import net.osmand.Collator;
|
||||
import net.osmand.CollatorStringMatcher;
|
||||
import net.osmand.CollatorStringMatcher.StringMatcherMode;
|
||||
import net.osmand.Location;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndPoiNameIndex.OsmAndPoiNameIndexData;
|
||||
import net.osmand.data.Amenity;
|
||||
import net.osmand.data.AmenityType;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.MapUtils;
|
||||
import net.sf.junidecode.Junidecode;
|
||||
|
@ -588,6 +590,17 @@ public class BinaryMapPoiReaderAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
private float dist(LatLon l, List<Location> locations) {
|
||||
float dist = Float.POSITIVE_INFINITY;
|
||||
// Special iterations because points stored by pairs!
|
||||
for (int i = 1; i < locations.size(); i += 2) {
|
||||
dist = Math.min(dist, (float) MapUtils.getOrthogonalDistance(
|
||||
l.getLatitude(), l.getLongitude(),
|
||||
locations.get(i - 1).getLatitude(), locations.get(i - 1).getLongitude(),
|
||||
locations.get(i).getLatitude(), locations.get(i).getLongitude()));
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
private Amenity readPoiPoint(int left31, int right31, int top31, int bottom31,
|
||||
int px, int py, int zoom, SearchRequest<Amenity> req, PoiRegion region, boolean checkBounds) throws IOException {
|
||||
Amenity am = null;
|
||||
|
@ -609,6 +622,19 @@ public class BinaryMapPoiReaderAdapter {
|
|||
am.setEnName(Junidecode.unidecode(am.getName()));
|
||||
}
|
||||
req.numberOfAcceptedObjects++;
|
||||
if (req.radius > 0) {
|
||||
LatLon loc = am.getLocation();
|
||||
List<Location> locs = req.tiles.get(req.getTileHashOnPath(loc.getLatitude(), loc.getLongitude()));
|
||||
if (locs == null) {
|
||||
return null;
|
||||
}
|
||||
float d = dist(am.getLocation(), locs);
|
||||
if (d > req.radius) {
|
||||
return null;
|
||||
} else {
|
||||
am.setDeviateDistance(d);
|
||||
}
|
||||
}
|
||||
return am;
|
||||
case OsmandOdb.OsmAndPoiBoxDataAtom.DX_FIELD_NUMBER :
|
||||
x = (codedIS.readSInt32() + (px << (24 - zoom))) << 7;
|
||||
|
@ -793,16 +819,16 @@ public class BinaryMapPoiReaderAdapter {
|
|||
case OsmandOdb.OsmAndPoiBox.SUBBOXES_FIELD_NUMBER: {
|
||||
int x = dx + (px << (zoom - pzoom));
|
||||
int y = dy + (py << (zoom - pzoom));
|
||||
if(checkBox){
|
||||
if (checkBox) {
|
||||
int xL = x << (31 - zoom);
|
||||
int xR = ((x + 1) << (31 - zoom)) - 1;
|
||||
int yT = y << (31 - zoom);
|
||||
int yB = ((y + 1) << (31 - zoom)) - 1;
|
||||
// check intersection
|
||||
if(left31 > xR || xL > right31 || bottom31 < yT || yB < top31){
|
||||
if (left31 > xR || xL > right31 || bottom31 < yT || yB < top31) {
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
req.numberOfAcceptedSubtrees++;
|
||||
checkBox = false;
|
||||
}
|
||||
|
@ -824,10 +850,20 @@ public class BinaryMapPoiReaderAdapter {
|
|||
int x = dx + (px << (zoom - pzoom));
|
||||
int y = dy + (py << (zoom - pzoom));
|
||||
long l = ((((x << zoom) | y) << 5) | zoom);
|
||||
offsetsMap.put(readInt(), l);
|
||||
if(skipTiles != null && zoom >= zoomToSkip){
|
||||
long val = ((((long) x) >> (zoom - zoomToSkip)) << zoomToSkip) | (((long) y) >> (zoom - zoomToSkip));
|
||||
skipTiles.add(val);
|
||||
boolean read = true;
|
||||
if(req.tiles != null) {
|
||||
int zx = x << (SearchRequest.ZOOM_TO_SEARCH_POI - zoom);
|
||||
int zy = y << (SearchRequest.ZOOM_TO_SEARCH_POI - zoom);
|
||||
read = req.tiles.contains((zx << SearchRequest.ZOOM_TO_SEARCH_POI) + zy);
|
||||
}
|
||||
int offset = readInt();
|
||||
if (read) {
|
||||
offsetsMap.put(offset, l);
|
||||
if (skipTiles != null && zoom >= zoomToSkip) {
|
||||
long val = ((((long) x) >> (zoom - zoomToSkip)) << zoomToSkip)
|
||||
| (((long) y) >> (zoom - zoomToSkip));
|
||||
skipTiles.add(val);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
|
|
|
@ -18,6 +18,7 @@ public class Amenity extends MapObject {
|
|||
// duplicate for fast access
|
||||
private String openingHours;
|
||||
private Map<String, String> additionalInfo;
|
||||
private double deviateDistance; // for search on path
|
||||
|
||||
public Amenity(){
|
||||
}
|
||||
|
@ -62,6 +63,13 @@ public class Amenity extends MapObject {
|
|||
openingHours = additionalInfo.get(OPENING_HOURS);
|
||||
}
|
||||
|
||||
public double getDeviateDistance() {
|
||||
return deviateDistance;
|
||||
}
|
||||
|
||||
public void setDeviateDistance(double deviateDistance) {
|
||||
this.deviateDistance = deviateDistance;
|
||||
}
|
||||
|
||||
public void setAdditionalInfo(String tag, String value) {
|
||||
if(this.additionalInfo == null){
|
||||
|
|
|
@ -220,6 +220,12 @@ public class MapUtils {
|
|||
}
|
||||
|
||||
|
||||
public static double getTileDistanceWidth(float zoom) {
|
||||
LatLon ll = new LatLon(30, MapUtils.getLongitudeFromTile(zoom, 0));
|
||||
LatLon ll2 = new LatLon(30, MapUtils.getLongitudeFromTile(zoom, 1));
|
||||
return getDistance(ll, ll2) ;
|
||||
}
|
||||
|
||||
public static double getLongitudeFromTile(float zoom, double x) {
|
||||
return x / getPowZoom(zoom) * 360.0 - 180.0;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<resources>
|
||||
<string name="app_name">OsmAnd~</string>
|
||||
<string name="app_version">1.8 alpha</string>
|
||||
<string name="app_version">1.9 alpha</string>
|
||||
<!-- Not translatable -->
|
||||
<string name="ga_api_key">UA-28342846-2</string>
|
||||
<string name="ga_dispatchPeriod">10</string>
|
||||
|
|
|
@ -820,6 +820,7 @@ public class MapActivityActions implements DialogProvider {
|
|||
} else {
|
||||
routingHelper.setRoutePlanningMode(true);
|
||||
routingHelper.setFollowingMode(false);
|
||||
routingHelper.setPauseNaviation(true);
|
||||
}
|
||||
mapActivity.getMapViewTrackingUtilities().switchToRoutePlanningMode();
|
||||
mapActivity.refreshMap();
|
||||
|
|
|
@ -39,6 +39,7 @@ public class SettingsMonitoringActivity extends SettingsBaseActivity {
|
|||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
requestWindowFeature(Window.FEATURE_PROGRESS);
|
||||
super.onCreate(savedInstanceState);
|
||||
setSupportProgressBarIndeterminateVisibility(false);
|
||||
getSupportActionBar().setTitle(R.string.monitoring_settings);
|
||||
|
|
|
@ -2,6 +2,7 @@ package net.osmand.plus.resources;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.Location;
|
||||
import net.osmand.ResultMatcher;
|
||||
import net.osmand.data.Amenity;
|
||||
import net.osmand.plus.PoiFilter;
|
||||
|
@ -20,5 +21,7 @@ public interface AmenityIndexRepository {
|
|||
public List<Amenity> searchAmenities(int stop, int sleft, int sbottom, int sright, int zoom, PoiFilter filter, List<Amenity> amenities,
|
||||
ResultMatcher<Amenity> matcher);
|
||||
|
||||
public List<Amenity> searchAmenitiesOnThePath(List<Location> locations, double radius, PoiFilter filter, ResultMatcher<Amenity> matcher);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.osmand.Location;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.ResultMatcher;
|
||||
import net.osmand.binary.BinaryMapIndexReader;
|
||||
|
@ -105,5 +106,30 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository {
|
|||
}
|
||||
return amenities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Amenity> searchAmenitiesOnThePath(List<Location> locations, double radius, final PoiFilter filter, ResultMatcher<Amenity> matcher) {
|
||||
long now = System.currentTimeMillis();
|
||||
SearchPoiTypeFilter poiTypeFilter = new SearchPoiTypeFilter(){
|
||||
@Override
|
||||
public boolean accept(AmenityType type, String subcategory) {
|
||||
return filter.acceptTypeSubtype(type, subcategory);
|
||||
}
|
||||
};
|
||||
List<Amenity> result = null;
|
||||
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(locations, radius,
|
||||
poiTypeFilter, filter == null ? matcher : filter.getResultMatcher(matcher));
|
||||
try {
|
||||
result = index.searchPoi(req);
|
||||
} catch (IOException e) {
|
||||
log.error("Error searching amenities", e); //$NON-NLS-1$
|
||||
return result;
|
||||
}
|
||||
if (log.isDebugEnabled() && result != null) {
|
||||
log.debug(String.format("Search done in %s ms found %s.", (System.currentTimeMillis() - now), result.size())); //$NON-NLS-1$
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ public class AsyncLoadingThread extends Thread {
|
|||
|
||||
private static final Log log = PlatformUtil.getLog(AsyncLoadingThread.class);
|
||||
|
||||
private Handler asyncLoadingPoi;
|
||||
private Handler asyncLoadingTransport;
|
||||
|
||||
Stack<Object> requests = new Stack<Object>();
|
||||
|
@ -43,11 +42,7 @@ public class AsyncLoadingThread extends Thread {
|
|||
this.resourceManger = resourceManger;
|
||||
}
|
||||
|
||||
private void startPoiLoadingThread() {
|
||||
HandlerThread h = new HandlerThread("Loading poi");
|
||||
h.start();
|
||||
asyncLoadingPoi = new Handler(h.getLooper());
|
||||
}
|
||||
|
||||
|
||||
private void startTransportLoadingThread() {
|
||||
HandlerThread h = new HandlerThread("Loading transport");
|
||||
|
@ -61,6 +56,8 @@ public class AsyncLoadingThread extends Thread {
|
|||
progress = BusyIndicator.STATUS_GREEN;
|
||||
} else if (resourceManger.getContext().getRoutingHelper().isRouteBeingCalculated()) {
|
||||
progress = BusyIndicator.STATUS_ORANGE;
|
||||
} else if (resourceManger.isSearchAmenitiesInProgress()) {
|
||||
progress = BusyIndicator.STATUS_BLACK;
|
||||
} else if (!requests.isEmpty()) {
|
||||
progress = BusyIndicator.STATUS_BLACK;
|
||||
} else if (transportLoadRequest != null && transportLoadRequest.isRunning()) {
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package net.osmand.plus.resources;
|
||||
|
||||
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -23,6 +21,7 @@ import net.osmand.AndroidUtils;
|
|||
import net.osmand.GeoidAltitudeCorrection;
|
||||
import net.osmand.IProgress;
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.Location;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.ResultMatcher;
|
||||
import net.osmand.binary.BinaryMapIndexReader;
|
||||
|
@ -271,6 +270,7 @@ public class ResourceManager {
|
|||
protected StringBuilder builder = new StringBuilder(40);
|
||||
protected char[] tileId = new char[120];
|
||||
private GeoidAltitudeCorrection geoidAltitudeCorrection;
|
||||
private boolean searchAmenitiesInProgress;
|
||||
|
||||
public synchronized String calculateTileId(ITileSource map, int x, int y, int zoom) {
|
||||
builder.setLength(0);
|
||||
|
@ -719,41 +719,47 @@ public class ResourceManager {
|
|||
public List<Amenity> searchAmenities(PoiFilter filter,
|
||||
double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, final ResultMatcher<Amenity> matcher) {
|
||||
final List<Amenity> amenities = new ArrayList<Amenity>();
|
||||
if(filter instanceof NameFinderPoiFilter || filter instanceof SearchByNameFilter){
|
||||
List<Amenity> tempResults = filter instanceof NameFinderPoiFilter ?
|
||||
((NameFinderPoiFilter) filter).getSearchedAmenities() :((SearchByNameFilter) filter).getSearchedAmenities() ;
|
||||
for(Amenity a : tempResults){
|
||||
LatLon l = a.getLocation();
|
||||
if(l != null && l.getLatitude() <= topLatitude && l.getLatitude() >= bottomLatitude && l.getLongitude() >= leftLongitude && l.getLongitude() <= rightLongitude){
|
||||
if(matcher.publish(a) ){
|
||||
amenities.add(a);
|
||||
searchAmenitiesInProgress = true;
|
||||
try {
|
||||
if (filter instanceof NameFinderPoiFilter || filter instanceof SearchByNameFilter) {
|
||||
List<Amenity> tempResults = filter instanceof NameFinderPoiFilter ? ((NameFinderPoiFilter) filter)
|
||||
.getSearchedAmenities() : ((SearchByNameFilter) filter).getSearchedAmenities();
|
||||
for (Amenity a : tempResults) {
|
||||
LatLon l = a.getLocation();
|
||||
if (l != null && l.getLatitude() <= topLatitude && l.getLatitude() >= bottomLatitude
|
||||
&& l.getLongitude() >= leftLongitude && l.getLongitude() <= rightLongitude) {
|
||||
if (matcher.publish(a)) {
|
||||
amenities.add(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final String filterByName = filter.getFilterByName();
|
||||
for (AmenityIndexRepository index : amenityRepositories) {
|
||||
if (index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)) {
|
||||
index.searchAmenities(MapUtils.get31TileNumberY(topLatitude),
|
||||
MapUtils.get31TileNumberX(leftLongitude), MapUtils.get31TileNumberY(bottomLatitude),
|
||||
MapUtils.get31TileNumberX(rightLongitude), zoom, filter, amenities,
|
||||
new ResultMatcher<Amenity>() {
|
||||
|
||||
@Override
|
||||
public boolean publish(Amenity object) {
|
||||
if (checkNameFilter(object, filterByName)) {
|
||||
return matcher.publish(object);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return matcher.isCancelled();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final String filterByName = filter.getFilterByName();
|
||||
for (AmenityIndexRepository index : amenityRepositories) {
|
||||
if (index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)) {
|
||||
index.searchAmenities(MapUtils.get31TileNumberY(topLatitude),
|
||||
MapUtils.get31TileNumberX(leftLongitude), MapUtils.get31TileNumberY(bottomLatitude),
|
||||
MapUtils.get31TileNumberX(rightLongitude), -1, filter, amenities,
|
||||
new ResultMatcher<Amenity>() {
|
||||
|
||||
@Override
|
||||
public boolean publish(Amenity object) {
|
||||
if (checkNameFilter(object, filterByName)) {
|
||||
return matcher.publish(object);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return matcher.isCancelled();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
searchAmenitiesInProgress = false;
|
||||
}
|
||||
return amenities;
|
||||
}
|
||||
|
@ -814,33 +820,40 @@ public class ResourceManager {
|
|||
return map;
|
||||
}
|
||||
|
||||
public void searchAmenitiesOnTheArea(TIntArrayList tiles16z, PoiFilter filter, ResultMatcher<Amenity> results) {
|
||||
if (tiles16z.size() > 0) {
|
||||
int z = 16;
|
||||
int x = tiles16z.get(0) >> z;
|
||||
int y = tiles16z.get(0) & ((1 << z) - 1);
|
||||
List<AmenityIndexRepository> repos = new ArrayList<AmenityIndexRepository>();
|
||||
double topLatitude = MapUtils.getLatitudeFromTile(z, y);
|
||||
double bottomLatitude = MapUtils.getLatitudeFromTile(z, y + 1);
|
||||
double leftLongitude = MapUtils.getLongitudeFromTile(z, x);
|
||||
double rightLongitude = MapUtils.getLongitudeFromTile(z, x + 1);
|
||||
for (int k = 1; k < tiles16z.size(); k++) {
|
||||
topLatitude = Math.max(topLatitude, MapUtils.getLatitudeFromTile(z, y));
|
||||
bottomLatitude = Math.min(bottomLatitude, MapUtils.getLatitudeFromTile(z, y + 1));
|
||||
leftLongitude = Math.min(leftLongitude, MapUtils.getLongitudeFromTile(z, x));
|
||||
rightLongitude = Math.max(rightLongitude, MapUtils.getLongitudeFromTile(z, x + 1));
|
||||
}
|
||||
for (AmenityIndexRepository index : amenityRepositories) {
|
||||
if (index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)) {
|
||||
repos.add(index);
|
||||
}
|
||||
}
|
||||
if (!repos.isEmpty()) {
|
||||
for(AmenityIndexRepository r : repos) {
|
||||
// r.searchAmenities(stop, sleft, sbottom, sright, zoom, filter, amenities, matcher)
|
||||
public List<Amenity> searchAmenitiesOnThePath(List<Location> locations, double radius, PoiFilter filter, ResultMatcher<Amenity> matcher) {
|
||||
searchAmenitiesInProgress = true;
|
||||
final List<Amenity> amenities = new ArrayList<Amenity>();
|
||||
try {
|
||||
if (locations != null && locations.size() > 0) {
|
||||
List<AmenityIndexRepository> repos = new ArrayList<AmenityIndexRepository>();
|
||||
double topLatitude = locations.get(0).getLatitude();
|
||||
double bottomLatitude = locations.get(0).getLatitude();
|
||||
double leftLongitude = locations.get(0).getLongitude();
|
||||
double rightLongitude = locations.get(0).getLongitude();
|
||||
for (Location l : locations) {
|
||||
topLatitude = Math.max(topLatitude, l.getLatitude());
|
||||
bottomLatitude = Math.min(bottomLatitude, l.getLatitude());
|
||||
leftLongitude = Math.min(leftLongitude, l.getLongitude());
|
||||
rightLongitude = Math.max(rightLongitude, l.getLongitude());
|
||||
}
|
||||
for (AmenityIndexRepository index : amenityRepositories) {
|
||||
if (index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)) {
|
||||
repos.add(index);
|
||||
}
|
||||
}
|
||||
if (!repos.isEmpty()) {
|
||||
for (AmenityIndexRepository r : repos) {
|
||||
List<Amenity> res = r.searchAmenitiesOnThePath(locations, radius, filter, matcher);
|
||||
if (res != null) {
|
||||
amenities.addAll(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}finally {
|
||||
searchAmenitiesInProgress = false;
|
||||
}
|
||||
return amenities;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////// Working with address ///////////////////////////////////////////
|
||||
|
@ -896,6 +909,10 @@ public class ResourceManager {
|
|||
renderer.interruptLoadingMap();
|
||||
}
|
||||
|
||||
public boolean isSearchAmenitiesInProgress() {
|
||||
return searchAmenitiesInProgress;
|
||||
}
|
||||
|
||||
public MapRenderRepositories getRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
|
|
@ -50,8 +50,8 @@ public class RoutingHelper {
|
|||
private OsmandApplication app;
|
||||
|
||||
private boolean isFollowingMode = false;
|
||||
|
||||
private boolean isRoutePlanningMode = false;
|
||||
private boolean isPauseNavigation = false;
|
||||
|
||||
private GPXRouteParamsBuilder currentGPXRoute = null;
|
||||
|
||||
|
@ -79,6 +79,7 @@ public class RoutingHelper {
|
|||
private RouteCalculationProgressCallback progressRoute;
|
||||
private SearchOnTheRouteHelper searchOnTheRouteHelper;
|
||||
|
||||
|
||||
// private ProgressBar progress;
|
||||
// private Handler progressHandler;
|
||||
|
||||
|
@ -101,8 +102,17 @@ public class RoutingHelper {
|
|||
return isFollowingMode;
|
||||
}
|
||||
|
||||
public void setPauseNaviation(boolean b) {
|
||||
this.isPauseNavigation = b;
|
||||
}
|
||||
|
||||
public boolean isPauseNavigation() {
|
||||
return isPauseNavigation;
|
||||
}
|
||||
|
||||
public void setFollowingMode(boolean follow) {
|
||||
isFollowingMode = follow;
|
||||
isPauseNavigation = false;
|
||||
if (!follow) {
|
||||
if (app.getNavigationService() != null) {
|
||||
app.getNavigationService().stopIfNeeded(app, NavigationService.USED_BY_NAVIGATION);
|
||||
|
@ -932,4 +942,5 @@ public class RoutingHelper {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,10 @@ import net.osmand.plus.R;
|
|||
import net.osmand.plus.activities.MapActivity;
|
||||
import net.osmand.plus.render.RenderingIcons;
|
||||
import net.osmand.plus.resources.ResourceManager;
|
||||
import net.osmand.plus.routing.RouteCalculationResult;
|
||||
import net.osmand.plus.routing.RoutingHelper;
|
||||
import net.osmand.plus.routing.RoutingHelper.IRouteInformationListener;
|
||||
import net.osmand.plus.routing.RoutingHelper.RouteCalculationProgressCallback;
|
||||
import net.osmand.plus.views.MapTextLayer.MapTextProvider;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
|
@ -36,7 +40,7 @@ import android.net.Uri;
|
|||
import android.widget.Toast;
|
||||
|
||||
public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.IContextMenuProvider,
|
||||
MapTextProvider<Amenity> {
|
||||
MapTextProvider<Amenity>, IRouteInformationListener {
|
||||
private static final int startZoom = 10;
|
||||
|
||||
public static final org.apache.commons.logging.Log log = PlatformUtil.getLog(POIMapLayer.class);
|
||||
|
@ -48,15 +52,20 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
|
|||
private final static int MAXIMUM_SHOW_AMENITIES = 5;
|
||||
|
||||
private ResourceManager resourceManager;
|
||||
private RoutingHelper routingHelper;
|
||||
private PoiFilter filter;
|
||||
private MapTextLayer mapTextLayer;
|
||||
|
||||
/// cache for displayed POI
|
||||
// Work with cache (for map copied from AmenityIndexRepositoryOdb)
|
||||
private MapLayerData<List<Amenity>> data;
|
||||
private boolean path = false;
|
||||
private double radius = 100;
|
||||
|
||||
|
||||
public POIMapLayer(MapActivity activity) {
|
||||
routingHelper = activity.getRoutingHelper();
|
||||
routingHelper.addListener(this);
|
||||
data = new OsmandMapLayer.MapLayerData<List<Amenity>>() {
|
||||
{
|
||||
ZOOM_THRESHOLD = 0;
|
||||
|
@ -70,19 +79,24 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
|
|||
@Override
|
||||
protected List<Amenity> calculateResult(RotatedTileBox tileBox) {
|
||||
QuadRect latLonBounds = tileBox.getLatLonBounds();
|
||||
return resourceManager.searchAmenities(filter, latLonBounds.top, latLonBounds.left,
|
||||
latLonBounds.bottom, latLonBounds.right, tileBox.getZoom(), new ResultMatcher<Amenity>() {
|
||||
if(path) {
|
||||
RouteCalculationResult result = routingHelper.getRoute();
|
||||
return resourceManager.searchAmenitiesOnThePath(result.getImmutableAllLocations(), radius, filter, null);
|
||||
} else {
|
||||
return resourceManager.searchAmenities(filter, latLonBounds.top, latLonBounds.left,
|
||||
latLonBounds.bottom, latLonBounds.right, tileBox.getZoom(), new ResultMatcher<Amenity>() {
|
||||
|
||||
@Override
|
||||
public boolean publish(Amenity object) {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean publish(Amenity object) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isInterrupted();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isInterrupted();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -92,9 +106,21 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
|
|||
}
|
||||
|
||||
public void setFilter(PoiFilter filter) {
|
||||
// TODO parameter
|
||||
this.filter = filter;
|
||||
// this.radius = 100;
|
||||
// this.path = true;
|
||||
this.path = false;
|
||||
data.clearCache();
|
||||
}
|
||||
|
||||
public void setFilter(PoiFilter filter, double radius) {
|
||||
this.filter = filter;
|
||||
this.radius = radius;
|
||||
this.path = true;
|
||||
data.clearCache();
|
||||
}
|
||||
|
||||
|
||||
public void getAmenityFromPoint(RotatedTileBox tb, PointF point, List<? super Amenity> am) {
|
||||
List<Amenity> objects = data.getResults();
|
||||
|
@ -224,6 +250,7 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
|
|||
|
||||
@Override
|
||||
public void destroyLayer() {
|
||||
routingHelper.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -317,7 +344,7 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public LatLon getTextLocation(Amenity o) {
|
||||
return o.getLocation();
|
||||
|
@ -333,4 +360,16 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
|
|||
return o.getName(view.getSettings().usingEnglishNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newRouteIsCalculated(boolean newRoute) {
|
||||
if(path) {
|
||||
data.clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeWasCancelled() {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ public class MapNavigateControl extends MapControls {
|
|||
startNavigation();
|
||||
}
|
||||
});
|
||||
if(!mapActivity.getRoutingHelper().isFollowingMode()) {
|
||||
if(!mapActivity.getRoutingHelper().isFollowingMode() && !mapActivity.getRoutingHelper().isPauseNavigation()) {
|
||||
startCounter();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue