Merge branch 'master' into color-pic

This commit is contained in:
androiddevkotlin 2021-03-02 08:31:15 +02:00
commit a4291472ad
9 changed files with 225 additions and 123 deletions

View file

@ -4,6 +4,7 @@ import net.osmand.Location;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion; import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule; import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
import net.osmand.data.LatLon;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils; import net.osmand.util.MapUtils;
import net.osmand.util.TransliterationHelper; import net.osmand.util.TransliterationHelper;
@ -37,7 +38,9 @@ public class RouteDataObject {
public int[] nameIds; public int[] nameIds;
// mixed array [0, height, cumulative_distance height, cumulative_distance, height, ...] - length is length(points)*2 // mixed array [0, height, cumulative_distance height, cumulative_distance, height, ...] - length is length(points)*2
public float[] heightDistanceArray = null; public float[] heightDistanceArray = null;
public float heightByCurrentLocation;
private static final Log LOG = PlatformUtil.getLog(RouteDataObject.class); private static final Log LOG = PlatformUtil.getLog(RouteDataObject.class);
public RouteDataObject(RouteRegion region) { public RouteDataObject(RouteRegion region) {
this.region = region; this.region = region;
} }
@ -124,7 +127,7 @@ public class RouteDataObject {
equals = this.pointTypes[i] == thatObj.pointTypes[i]; equals = this.pointTypes[i] == thatObj.pointTypes[i];
} else if (pointTypes[i].length != thatObj.pointTypes[i].length) { } else if (pointTypes[i].length != thatObj.pointTypes[i].length) {
equals = false; equals = false;
} else { } else {
for (int j = 0; j < this.pointTypes[i].length && equals; j++) { for (int j = 0; j < this.pointTypes[i].length && equals; j++) {
String thisTag = region.routeEncodingRules.get(pointTypes[i][j]).getTag(); String thisTag = region.routeEncodingRules.get(pointTypes[i][j]).getTag();
String thisValue = region.routeEncodingRules.get(pointTypes[i][j]).getValue(); String thisValue = region.routeEncodingRules.get(pointTypes[i][j]).getValue();
@ -147,7 +150,7 @@ public class RouteDataObject {
equals = this.pointNameTypes[i] == thatObj.pointNameTypes[i]; equals = this.pointNameTypes[i] == thatObj.pointNameTypes[i];
} else if (pointNameTypes[i].length != thatObj.pointNameTypes[i].length) { } else if (pointNameTypes[i].length != thatObj.pointNameTypes[i].length) {
equals = false; equals = false;
} else { } else {
for (int j = 0; j < this.pointNameTypes[i].length && equals; j++) { for (int j = 0; j < this.pointNameTypes[i].length && equals; j++) {
String thisTag = region.routeEncodingRules.get(pointNameTypes[i][j]).getTag(); String thisTag = region.routeEncodingRules.get(pointNameTypes[i][j]).getTag();
String thisValue = pointNames[i][j]; String thisValue = pointNames[i][j];
@ -165,53 +168,67 @@ public class RouteDataObject {
} }
public float[] calculateHeightArray() { public float[] calculateHeightArray() {
if(heightDistanceArray != null) { return calculateHeightArray(null);
}
public float[] calculateHeightArray(LatLon currentLocation) {
if (heightDistanceArray != null) {
return heightDistanceArray; return heightDistanceArray;
} }
int startHeight = Algorithms.parseIntSilently(getValue("osmand_ele_start"), HEIGHT_UNDEFINED); int startHeight = Algorithms.parseIntSilently(getValue("osmand_ele_start"), HEIGHT_UNDEFINED);
int endHeight = Algorithms.parseIntSilently(getValue("osmand_ele_end"), startHeight); int endHeight = Algorithms.parseIntSilently(getValue("osmand_ele_end"), startHeight);
if(startHeight == HEIGHT_UNDEFINED) { if (startHeight == HEIGHT_UNDEFINED) {
heightDistanceArray = new float[0]; heightDistanceArray = new float[0];
return heightDistanceArray; return heightDistanceArray;
} }
heightDistanceArray = new float[2*getPointsLength()]; heightDistanceArray = new float[2 * getPointsLength()];
double plon = 0; double plon = 0;
double plat = 0; double plat = 0;
float prevHeight = startHeight; float prevHeight = heightByCurrentLocation = startHeight;
for(int k = 0; k < getPointsLength(); k++) { double prevDistance = 0;
for (int k = 0; k < getPointsLength(); k++) {
double lon = MapUtils.get31LongitudeX(getPoint31XTile(k)); double lon = MapUtils.get31LongitudeX(getPoint31XTile(k));
double lat = MapUtils.get31LatitudeY(getPoint31YTile(k)); double lat = MapUtils.get31LatitudeY(getPoint31YTile(k));
if(k > 0) { if (k > 0) {
double dd = MapUtils.getDistance(plat, plon, lat, lon); double dd = MapUtils.getDistance(plat, plon, lat, lon);
float height = HEIGHT_UNDEFINED; float height = HEIGHT_UNDEFINED;
if(k == getPointsLength() - 1) { if (k == getPointsLength() - 1) {
height = endHeight; height = endHeight;
} else { } else {
String asc = getValue(k, "osmand_ele_asc"); String asc = getValue(k, "osmand_ele_asc");
if(asc != null && asc.length() > 0) { if (asc != null && asc.length() > 0) {
height = (prevHeight + Float.parseFloat(asc)); height = (prevHeight + Float.parseFloat(asc));
} else { } else {
String desc = getValue(k, "osmand_ele_desc"); String desc = getValue(k, "osmand_ele_desc");
if(desc != null && desc.length() > 0) { if (desc != null && desc.length() > 0) {
height = (prevHeight - Float.parseFloat(desc)); height = (prevHeight - Float.parseFloat(desc));
} }
} }
} }
heightDistanceArray[2*k] = (float) dd; heightDistanceArray[2 * k] = (float) dd;
heightDistanceArray[2*k+1] = height; heightDistanceArray[2 * k + 1] = height;
if(height != HEIGHT_UNDEFINED) {
if (currentLocation != null) {
double distance = MapUtils.getDistance(currentLocation, lat, lon);
if (height != HEIGHT_UNDEFINED && distance < prevDistance) {
prevDistance = distance;
heightByCurrentLocation = height;
}
}
if (height != HEIGHT_UNDEFINED) {
// interpolate undefined // interpolate undefined
double totalDistance = dd; double totalDistance = dd;
int startUndefined = k; int startUndefined = k;
while(startUndefined - 1 >= 0 && heightDistanceArray[2*(startUndefined - 1)+1] == HEIGHT_UNDEFINED) { while (startUndefined - 1 >= 0 && heightDistanceArray[2 * (startUndefined - 1) + 1] == HEIGHT_UNDEFINED) {
startUndefined --; startUndefined--;
totalDistance += heightDistanceArray[2*(startUndefined)]; totalDistance += heightDistanceArray[2 * (startUndefined)];
} }
if(totalDistance > 0) { if (totalDistance > 0) {
double angle = (height - prevHeight) / totalDistance; double angle = (height - prevHeight) / totalDistance;
for(int j = startUndefined; j < k; j++) { for (int j = startUndefined; j < k; j++) {
heightDistanceArray[2*j+1] = (float) ((heightDistanceArray[2*j] * angle) + heightDistanceArray[2*j-1]); heightDistanceArray[2 * j + 1] = (float) ((heightDistanceArray[2 * j] * angle) + heightDistanceArray[2 * j - 1]);
} }
} }
prevHeight = height; prevHeight = height;
@ -223,6 +240,9 @@ public class RouteDataObject {
} }
plat = lat; plat = lat;
plon = lon; plon = lon;
if (currentLocation != null) {
prevDistance = MapUtils.getDistance(currentLocation, plat, plon);
}
} }
return heightDistanceArray; return heightDistanceArray;
} }
@ -231,34 +251,34 @@ public class RouteDataObject {
return id; return id;
} }
public String getName(){ public String getName() {
if(names != null ) { if (names != null) {
return names.get(region.nameTypeRule); return names.get(region.nameTypeRule);
} }
return null; return null;
} }
public String getName(String lang){ public String getName(String lang) {
return getName(lang, false); return getName(lang, false);
} }
public String getName(String lang, boolean transliterate){ public String getName(String lang, boolean transliterate) {
if(names != null ) { if (names != null) {
if(Algorithms.isEmpty(lang)) { if (Algorithms.isEmpty(lang)) {
return names.get(region.nameTypeRule); return names.get(region.nameTypeRule);
} }
int[] kt = names.keys(); int[] kt = names.keys();
for(int i = 0 ; i < kt.length; i++) { for (int i = 0; i < kt.length; i++) {
int k = kt[i]; int k = kt[i];
if(region.routeEncodingRules.size() > k) { if (region.routeEncodingRules.size() > k) {
if(("name:"+lang).equals(region.routeEncodingRules.get(k).getTag())) { if (("name:" + lang).equals(region.routeEncodingRules.get(k).getTag())) {
return names.get(k); return names.get(k);
} }
} }
} }
String nmDef = names.get(region.nameTypeRule); String nmDef = names.get(region.nameTypeRule);
if(transliterate && nmDef != null && nmDef.length() > 0) { if (transliterate && nmDef != null && nmDef.length() > 0) {
return TransliterationHelper.transliterate(nmDef); return TransliterationHelper.transliterate(nmDef);
} }
return nmDef; return nmDef;
@ -279,20 +299,20 @@ public class RouteDataObject {
// return getDestinationRef(direction); // return getDestinationRef(direction);
//} //}
if (names != null) { if (names != null) {
if(Algorithms.isEmpty(lang)) { if (Algorithms.isEmpty(lang)) {
return names.get(region.refTypeRule); return names.get(region.refTypeRule);
} }
int[] kt = names.keys(); int[] kt = names.keys();
for(int i = 0 ; i < kt.length; i++) { for (int i = 0; i < kt.length; i++) {
int k = kt[i]; int k = kt[i];
if(region.routeEncodingRules.size() > k) { if (region.routeEncodingRules.size() > k) {
if(("ref:"+lang).equals(region.routeEncodingRules.get(k).getTag())) { if (("ref:" + lang).equals(region.routeEncodingRules.get(k).getTag())) {
return names.get(k); return names.get(k);
} }
} }
} }
String refDefault = names.get(region.refTypeRule); String refDefault = names.get(region.refTypeRule);
if(transliterate && refDefault != null && refDefault.length() > 0) { if (transliterate && refDefault != null && refDefault.length() > 0) {
return TransliterationHelper.transliterate(refDefault); return TransliterationHelper.transliterate(refDefault);
} }
return refDefault; return refDefault;
@ -307,13 +327,13 @@ public class RouteDataObject {
String refTagDefault = "destination:ref"; String refTagDefault = "destination:ref";
String refDefault = null; String refDefault = null;
for(int i = 0 ; i < kt.length; i++) { for (int i = 0; i < kt.length; i++) {
int k = kt[i]; int k = kt[i];
if(region.routeEncodingRules.size() > k) { if (region.routeEncodingRules.size() > k) {
if(refTag.equals(region.routeEncodingRules.get(k).getTag())) { if (refTag.equals(region.routeEncodingRules.get(k).getTag())) {
return names.get(k); return names.get(k);
} }
if(refTagDefault.equals(region.routeEncodingRules.get(k).getTag())) { if (refTagDefault.equals(region.routeEncodingRules.get(k).getTag())) {
refDefault = names.get(k); refDefault = names.get(k);
} }
} }
@ -326,12 +346,12 @@ public class RouteDataObject {
return null; return null;
} }
public String getDestinationName(String lang, boolean transliterate, boolean direction){ public String getDestinationName(String lang, boolean transliterate, boolean direction) {
//Issue #3289: Treat destination:ref like a destination, not like a ref //Issue #3289: Treat destination:ref like a destination, not like a ref
String destRef = ((getDestinationRef(direction) == null) || getDestinationRef(direction).equals(getRef(lang, transliterate, direction))) ? "" : getDestinationRef(direction); String destRef = ((getDestinationRef(direction) == null) || getDestinationRef(direction).equals(getRef(lang, transliterate, direction))) ? "" : getDestinationRef(direction);
String destRef1 = Algorithms.isEmpty(destRef) ? "" : destRef + ", "; String destRef1 = Algorithms.isEmpty(destRef) ? "" : destRef + ", ";
if(names != null) { if (names != null) {
int[] kt = names.keys(); int[] kt = names.keys();
// Issue #3181: Parse destination keys in this order: // Issue #3181: Parse destination keys in this order:
@ -341,35 +361,35 @@ public class RouteDataObject {
// destination // destination
String destinationTagLangFB = "destination:lang:XX"; String destinationTagLangFB = "destination:lang:XX";
if(!Algorithms.isEmpty(lang)) { if (!Algorithms.isEmpty(lang)) {
destinationTagLangFB = (direction == true) ? "destination:lang:" + lang + ":forward" : "destination:lang:" + lang + ":backward"; destinationTagLangFB = (direction == true) ? "destination:lang:" + lang + ":forward" : "destination:lang:" + lang + ":backward";
} }
String destinationTagFB = (direction == true) ? "destination:forward" : "destination:backward"; String destinationTagFB = (direction == true) ? "destination:forward" : "destination:backward";
String destinationTagLang = "destination:lang:XX"; String destinationTagLang = "destination:lang:XX";
if(!Algorithms.isEmpty(lang)) { if (!Algorithms.isEmpty(lang)) {
destinationTagLang = "destination:lang:" + lang; destinationTagLang = "destination:lang:" + lang;
} }
String destinationTagDefault = "destination"; String destinationTagDefault = "destination";
String destinationDefault = null; String destinationDefault = null;
for(int i = 0 ; i < kt.length; i++) { for (int i = 0; i < kt.length; i++) {
int k = kt[i]; int k = kt[i];
if(region.routeEncodingRules.size() > k) { if (region.routeEncodingRules.size() > k) {
if(!Algorithms.isEmpty(lang) && destinationTagLangFB.equals(region.routeEncodingRules.get(k).getTag())) { if (!Algorithms.isEmpty(lang) && destinationTagLangFB.equals(region.routeEncodingRules.get(k).getTag())) {
return destRef1 + ((transliterate) ? TransliterationHelper.transliterate(names.get(k)) : names.get(k)); return destRef1 + ((transliterate) ? TransliterationHelper.transliterate(names.get(k)) : names.get(k));
} }
if(destinationTagFB.equals(region.routeEncodingRules.get(k).getTag())) { if (destinationTagFB.equals(region.routeEncodingRules.get(k).getTag())) {
return destRef1 + ((transliterate) ? TransliterationHelper.transliterate(names.get(k)) : names.get(k)); return destRef1 + ((transliterate) ? TransliterationHelper.transliterate(names.get(k)) : names.get(k));
} }
if(!Algorithms.isEmpty(lang) && destinationTagLang.equals(region.routeEncodingRules.get(k).getTag())) { if (!Algorithms.isEmpty(lang) && destinationTagLang.equals(region.routeEncodingRules.get(k).getTag())) {
return destRef1 + ((transliterate) ? TransliterationHelper.transliterate(names.get(k)) : names.get(k)); return destRef1 + ((transliterate) ? TransliterationHelper.transliterate(names.get(k)) : names.get(k));
} }
if(destinationTagDefault.equals(region.routeEncodingRules.get(k).getTag())) { if (destinationTagDefault.equals(region.routeEncodingRules.get(k).getTag())) {
destinationDefault = names.get(k); destinationDefault = names.get(k);
} }
} }
} }
if(destinationDefault != null) { if (destinationDefault != null) {
return destRef1 + ((transliterate) ? TransliterationHelper.transliterate(destinationDefault) : destinationDefault); return destRef1 + ((transliterate) ? TransliterationHelper.transliterate(destinationDefault) : destinationDefault);
} }
} }
@ -400,14 +420,14 @@ public class RouteDataObject {
RestrictionInfo ri = new RestrictionInfo(); RestrictionInfo ri = new RestrictionInfo();
ri.toWay = getRestrictionId(k); ri.toWay = getRestrictionId(k);
ri.type = getRestrictionType(k); ri.type = getRestrictionType(k);
if(restrictionsVia != null && k < restrictionsVia.length) { if (restrictionsVia != null && k < restrictionsVia.length) {
ri.viaWay = restrictionsVia[k]; ri.viaWay = restrictionsVia[k];
} }
return ri; return ri;
} }
public long getRestrictionVia(int i) { public long getRestrictionVia(int i) {
if(restrictionsVia != null && restrictionsVia.length > i) { if (restrictionsVia != null && restrictionsVia.length > i) {
return restrictionsVia[i]; return restrictionsVia[i];
} }
return 0; return 0;
@ -441,7 +461,7 @@ public class RouteDataObject {
} }
if (insNames) { if (insNames) {
pointNames = new String[opointNames.length + 1][]; pointNames = new String[opointNames.length + 1][];
pointNameTypes = new int[opointNameTypes.length +1][]; pointNameTypes = new int[opointNameTypes.length + 1][];
} }
int i = 0; int i = 0;
for (; i < pos; i++) { for (; i < pos; i++) {
@ -590,7 +610,7 @@ public class RouteDataObject {
} }
public static float parseSpeed(String v, float def) { public static float parseSpeed(String v, float def) {
if(v.equals("none")) { if (v.equals("none")) {
return RouteDataObject.NONE_MAX_SPEED; return RouteDataObject.NONE_MAX_SPEED;
} else { } else {
int i = Algorithms.findFirstNumberEndIndex(v); int i = Algorithms.findFirstNumberEndIndex(v);
@ -614,20 +634,20 @@ public class RouteDataObject {
f += Float.parseFloat(v.substring(0, i)); f += Float.parseFloat(v.substring(0, i));
String pref = v.substring(i, v.length()).trim(); String pref = v.substring(i, v.length()).trim();
float add = 0; float add = 0;
for(int ik = 0; ik < pref.length(); ik++) { for (int ik = 0; ik < pref.length(); ik++) {
if(Algorithms.isDigit(pref.charAt(ik)) || pref.charAt(ik) == '.' || pref.charAt(ik) == '-') { if (Algorithms.isDigit(pref.charAt(ik)) || pref.charAt(ik) == '.' || pref.charAt(ik) == '-') {
int first = Algorithms.findFirstNumberEndIndex(pref.substring(ik)); int first = Algorithms.findFirstNumberEndIndex(pref.substring(ik));
if(first != -1) { if (first != -1) {
add = parseLength(pref.substring(ik), 0); add = parseLength(pref.substring(ik), 0);
pref = pref.substring(0, ik); pref = pref.substring(0, ik);
} }
break; break;
} }
} }
if(pref.contains("km")) { if (pref.contains("km")) {
f *= 1000; f *= 1000;
} }
if(pref.contains("\"") || pref.contains("in")) { if (pref.contains("\"") || pref.contains("in")) {
f *= 0.0254; f *= 0.0254;
} else if (pref.contains("\'") || pref.contains("ft") || pref.contains("feet")) { } else if (pref.contains("\'") || pref.contains("ft") || pref.contains("feet")) {
// foot to meters // foot to meters
@ -673,27 +693,27 @@ public class RouteDataObject {
return false; return false;
} }
public boolean roundabout(){ public boolean roundabout() {
int sz = types.length; int sz = types.length;
for(int i=0; i<sz; i++) { for (int i = 0; i < sz; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]); RouteTypeRule r = region.quickGetEncodingRule(types[i]);
if(r.roundabout()) { if (r.roundabout()) {
return true; return true;
} else if(r.onewayDirection() != 0 && loop()) { } else if (r.onewayDirection() != 0 && loop()) {
return true; return true;
} }
} }
return false; return false;
} }
public boolean tunnel(){ public boolean tunnel() {
int sz = types.length; int sz = types.length;
for(int i=0; i<sz; i++) { for (int i = 0; i < sz; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]); RouteTypeRule r = region.quickGetEncodingRule(types[i]);
if(r.getTag().equals("tunnel") && r.getValue().equals("yes")) { if (r.getTag().equals("tunnel") && r.getValue().equals("yes")) {
return true; return true;
} }
if(r.getTag().equals("layer") && r.getValue().equals("-1")) { if (r.getTag().equals("layer") && r.getValue().equals("-1")) {
return true; return true;
} }
} }
@ -882,7 +902,7 @@ public class RouteDataObject {
public boolean bearingVsRouteDirection(Location loc) { public boolean bearingVsRouteDirection(Location loc) {
boolean direction = true; boolean direction = true;
if(loc != null && loc.hasBearing()) { if (loc != null && loc.hasBearing()) {
double diff = MapUtils.alignAngleDifference(directionRoute(0, true) - loc.getBearing() / 180f * Math.PI); double diff = MapUtils.alignAngleDifference(directionRoute(0, true) - loc.getBearing() / 180f * Math.PI);
direction = Math.abs(diff) < Math.PI / 2f; direction = Math.abs(diff) < Math.PI / 2f;
} }
@ -932,13 +952,13 @@ public class RouteDataObject {
} }
public double distance(int startPoint, int endPoint) { public double distance(int startPoint, int endPoint) {
if(startPoint > endPoint) { if (startPoint > endPoint) {
int k = endPoint; int k = endPoint;
endPoint = startPoint; endPoint = startPoint;
startPoint = k; startPoint = k;
} }
double d = 0; double d = 0;
for(int k = startPoint; k < endPoint && k < getPointsLength() -1; k++) { for (int k = startPoint; k < endPoint && k < getPointsLength() - 1; k++) {
int x = getPoint31XTile(k); int x = getPoint31XTile(k);
int y = getPoint31YTile(k); int y = getPoint31YTile(k);
int kx = getPoint31XTile(k + 1); int kx = getPoint31XTile(k + 1);
@ -974,16 +994,16 @@ public class RouteDataObject {
// translate into meters // translate into meters
total += simplifyDistance(x, y, px, py); total += simplifyDistance(x, y, px, py);
} while (total < dist); } while (total < dist);
return -Math.atan2( x - px, y - py ); return -Math.atan2(x - px, y - py);
} }
private double simplifyDistance(int x, int y, int px, int py) { private double simplifyDistance(int x, int y, int px, int py) {
return Math.abs(px - x) * 0.011d + Math.abs(py - y) * 0.01863d; return Math.abs(px - x) * 0.011d + Math.abs(py - y) * 0.01863d;
} }
private static void assertTrueLength(String vl, float exp){ private static void assertTrueLength(String vl, float exp) {
float dest = parseLength(vl, 0); float dest = parseLength(vl, 0);
if(exp != dest) { if (exp != dest) {
System.err.println("FAIL " + vl + " " + dest); System.err.println("FAIL " + vl + " " + dest);
} else { } else {
System.out.println("OK " + vl); System.out.println("OK " + vl);
@ -992,24 +1012,24 @@ public class RouteDataObject {
public static void main(String[] args) { public static void main(String[] args) {
assertTrueLength("10 km", 10000); assertTrueLength("10 km", 10000);
assertTrueLength("0.01 km", 10); assertTrueLength("0.01 km", 10);
assertTrueLength("0.01 km 10 m", 20); assertTrueLength("0.01 km 10 m", 20);
assertTrueLength("10 m", 10); assertTrueLength("10 m", 10);
assertTrueLength("10m", 10); assertTrueLength("10m", 10);
assertTrueLength("3.4 m", 3.4f); assertTrueLength("3.4 m", 3.4f);
assertTrueLength("3.40 m", 3.4f); assertTrueLength("3.40 m", 3.4f);
assertTrueLength("10 m 10m", 20); assertTrueLength("10 m 10m", 20);
assertTrueLength("14'10\"", 4.5212f); assertTrueLength("14'10\"", 4.5212f);
assertTrueLength("14.5'", 4.4196f); assertTrueLength("14.5'", 4.4196f);
assertTrueLength("14.5 ft", 4.4196f); assertTrueLength("14.5 ft", 4.4196f);
assertTrueLength("14'0\"", 4.2672f); assertTrueLength("14'0\"", 4.2672f);
assertTrueLength("15ft", 4.572f); assertTrueLength("15ft", 4.572f);
assertTrueLength("15 ft 1 in", 4.5974f); assertTrueLength("15 ft 1 in", 4.5974f);
assertTrueLength("4.1 metres", 4.1f); assertTrueLength("4.1 metres", 4.1f);
assertTrueLength("14'0''", 4.2672f); assertTrueLength("14'0''", 4.2672f);
assertTrueLength("14 feet", 4.2672f); assertTrueLength("14 feet", 4.2672f);
assertTrueLength("14 mile", 22530.76f); assertTrueLength("14 mile", 22530.76f);
assertTrueLength("14 cm", 0.14f); assertTrueLength("14 cm", 0.14f);
// float badValue = -1; // float badValue = -1;
// assertTrueLength("none", badValue); // assertTrueLength("none", badValue);
@ -1054,7 +1074,7 @@ public class RouteDataObject {
public RestrictionInfo next; // optional to simulate linked list public RestrictionInfo next; // optional to simulate linked list
public int length() { public int length() {
if(next == null) { if (next == null) {
return 1; return 1;
} }
return next.length() + 1; return next.length() + 1;
@ -1064,16 +1084,16 @@ public class RouteDataObject {
public void setRestriction(int k, long to, int type, long viaWay) { public void setRestriction(int k, long to, int type, long viaWay) {
long valto = (to << RouteDataObject.RESTRICTION_SHIFT) | ((long) type & RouteDataObject.RESTRICTION_MASK); long valto = (to << RouteDataObject.RESTRICTION_SHIFT) | ((long) type & RouteDataObject.RESTRICTION_MASK);
restrictions[k] = valto; restrictions[k] = valto;
if(viaWay != 0) { if (viaWay != 0) {
setRestrictionVia(k, viaWay); setRestrictionVia(k, viaWay);
} }
} }
public void setRestrictionVia(int k, long viaWay) { public void setRestrictionVia(int k, long viaWay) {
if(restrictionsVia != null) { if (restrictionsVia != null) {
long[] nrestrictionsVia = new long[Math.max(k + 1, restrictions.length)]; long[] nrestrictionsVia = new long[Math.max(k + 1, restrictions.length)];
System.arraycopy(restrictions, 0, nrestrictionsVia, 0, restrictions.length); System.arraycopy(restrictions, 0, nrestrictionsVia, 0, restrictions.length);
restrictionsVia = nrestrictionsVia; restrictionsVia = nrestrictionsVia;
} else { } else {
restrictionsVia = new long[k + 1]; restrictionsVia = new long[k + 1];
} }

View file

@ -11,6 +11,9 @@ import androidx.annotation.Nullable;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
import net.osmand.GPXUtilities.WptPt; import net.osmand.GPXUtilities.WptPt;
import net.osmand.Location;
import net.osmand.ResultMatcher;
import net.osmand.binary.RouteDataObject;
import net.osmand.plus.FavouritesDbHelper; import net.osmand.plus.FavouritesDbHelper;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.BooleanPreference; import net.osmand.plus.settings.backend.BooleanPreference;
@ -42,6 +45,8 @@ public class FavouritePoint implements Serializable, LocationPoint {
private boolean visible = true; private boolean visible = true;
private SpecialPointType specialPointType = null; private SpecialPointType specialPointType = null;
private BackgroundType backgroundType = null; private BackgroundType backgroundType = null;
private double altitude;
private long timestamp;
public FavouritePoint() { public FavouritePoint() {
} }
@ -50,10 +55,24 @@ public class FavouritePoint implements Serializable, LocationPoint {
this.latitude = latitude; this.latitude = latitude;
this.longitude = longitude; this.longitude = longitude;
this.category = category; this.category = category;
if(name == null) { if (name == null) {
name = ""; name = "";
} }
this.name = name; this.name = name;
timestamp = System.currentTimeMillis();
initPersonalType();
}
public FavouritePoint(double latitude, double longitude, String name, String category, double altitude, long timestamp) {
this.latitude = latitude;
this.longitude = longitude;
this.category = category;
if (name == null) {
name = "";
}
this.name = name;
this.altitude = altitude;
this.timestamp = timestamp != 0 ? timestamp : System.currentTimeMillis();
initPersonalType(); initPersonalType();
} }
@ -69,25 +88,56 @@ public class FavouritePoint implements Serializable, LocationPoint {
this.address = favouritePoint.address; this.address = favouritePoint.address;
this.iconId = favouritePoint.iconId; this.iconId = favouritePoint.iconId;
this.backgroundType = favouritePoint.backgroundType; this.backgroundType = favouritePoint.backgroundType;
this.altitude = favouritePoint.altitude;
this.timestamp = favouritePoint.timestamp;
initPersonalType(); initPersonalType();
} }
private void initPersonalType() { private void initPersonalType() {
if(FavouritesDbHelper.FavoriteGroup.PERSONAL_CATEGORY.equals(category)) { if (FavouritesDbHelper.FavoriteGroup.PERSONAL_CATEGORY.equals(category)) {
for(SpecialPointType p : SpecialPointType.values()) { for (SpecialPointType p : SpecialPointType.values()) {
if(p.typeName.equals(this.name)) { if (p.typeName.equals(this.name)) {
this.specialPointType = p; this.specialPointType = p;
} }
} }
} }
} }
public void initAltitude(OsmandApplication app) {
initAltitude(app, null);
}
public void initAltitude(OsmandApplication app, final Runnable callback) {
Location location = new Location("", latitude, longitude);
app.getLocationProvider().getRouteSegment(location, null, false,
new ResultMatcher<RouteDataObject>() {
@Override
public boolean publish(RouteDataObject routeDataObject) {
if (routeDataObject != null) {
LatLon latLon = new LatLon(latitude, longitude);
routeDataObject.calculateHeightArray(latLon);
altitude = routeDataObject.heightByCurrentLocation;
}
if (callback != null) {
callback.run();
}
return true;
}
@Override
public boolean isCancelled() {
return false;
}
});
}
public SpecialPointType getSpecialPointType() { public SpecialPointType getSpecialPointType() {
return specialPointType; return specialPointType;
} }
public int getColor() { public int getColor() {
return color; return color;
} }
@Nullable @Nullable
@ -171,6 +221,22 @@ public class FavouritePoint implements Serializable, LocationPoint {
this.longitude = longitude; this.longitude = longitude;
} }
public double getAltitude() {
return altitude;
}
public void setAltitude(double altitude) {
this.altitude = altitude;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public String getCategory() { public String getCategory() {
return category; return category;
} }
@ -200,7 +266,7 @@ public class FavouritePoint implements Serializable, LocationPoint {
initPersonalType(); initPersonalType();
} }
public String getDescription () { public String getDescription() {
return description; return description;
} }
@ -256,7 +322,8 @@ public class FavouritePoint implements Serializable, LocationPoint {
} else if (!originObjectName.equals(fp.originObjectName)) } else if (!originObjectName.equals(fp.originObjectName))
return false; return false;
return (this.latitude == fp.latitude) && (this.longitude == fp.longitude); return (this.latitude == fp.latitude) && (this.longitude == fp.longitude) &&
(this.altitude == fp.altitude) && (this.timestamp == fp.timestamp);
} }
@Override @Override
@ -265,6 +332,8 @@ public class FavouritePoint implements Serializable, LocationPoint {
int result = 1; int result = 1;
result = prime * result + (int) Math.floor(latitude * 10000); result = prime * result + (int) Math.floor(latitude * 10000);
result = prime * result + (int) Math.floor(longitude * 10000); result = prime * result + (int) Math.floor(longitude * 10000);
result = prime * result + (int) Math.floor(altitude * 10000);
result = prime * result + (int) Math.floor(timestamp * 10000);
result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((category == null) ? 0 : category.hashCode()); result = prime * result + ((category == null) ? 0 : category.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode()); result = prime * result + ((description == null) ? 0 : description.hashCode());
@ -289,7 +358,9 @@ public class FavouritePoint implements Serializable, LocationPoint {
this.iconId = iconId; this.iconId = iconId;
} }
public String getCategory() { return FavouritesDbHelper.FavoriteGroup.PERSONAL_CATEGORY; } public String getCategory() {
return FavouritesDbHelper.FavoriteGroup.PERSONAL_CATEGORY;
}
public String getName() { public String getName() {
return typeName; return typeName;
@ -384,7 +455,7 @@ public class FavouritePoint implements Serializable, LocationPoint {
name = ""; name = "";
} }
FavouritePoint fp; FavouritePoint fp;
fp = new FavouritePoint(pt.lat, pt.lon, name, categoryName); fp = new FavouritePoint(pt.lat, pt.lon, name, categoryName, pt.ele, pt.time);
fp.setDescription(pt.desc); fp.setDescription(pt.desc);
if (pt.comment != null) { if (pt.comment != null) {
fp.setOriginObjectName(pt.comment); fp.setOriginObjectName(pt.comment);
@ -405,6 +476,8 @@ public class FavouritePoint implements Serializable, LocationPoint {
WptPt pt = new WptPt(); WptPt pt = new WptPt();
pt.lat = getLatitude(); pt.lat = getLatitude();
pt.lon = getLongitude(); pt.lon = getLongitude();
pt.ele = getAltitude();
pt.time = getTimestamp();
if (!isVisible()) { if (!isVisible()) {
pt.getExtensionsToWrite().put(HIDDEN, "true"); pt.getExtensionsToWrite().put(HIDDEN, "true");
} }

View file

@ -361,6 +361,9 @@ public class FavouritesDbHelper {
} }
public boolean addFavourite(FavouritePoint p, boolean saveImmediately) { public boolean addFavourite(FavouritePoint p, boolean saveImmediately) {
if (Double.isNaN(p.getAltitude()) || p.getAltitude() == 0) {
p.initAltitude(context);
}
if (p.getName().isEmpty() && flatGroups.containsKey(p.getCategory())) { if (p.getName().isEmpty() && flatGroups.containsKey(p.getCategory())) {
return true; return true;
} }
@ -545,6 +548,7 @@ public class FavouritesDbHelper {
cancelAddressRequest(p); cancelAddressRequest(p);
p.setLatitude(lat); p.setLatitude(lat);
p.setLongitude(lon); p.setLongitude(lon);
p.initAltitude(context);
if (description != null) { if (description != null) {
p.setDescription(description); p.setDescription(description);
} }

View file

@ -24,7 +24,7 @@ class FavoritesImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
private boolean forceImportFavourites; private boolean forceImportFavourites;
public FavoritesImportTask(@NonNull FragmentActivity activity, @NonNull GPXFile gpxFile, public FavoritesImportTask(@NonNull FragmentActivity activity, @NonNull GPXFile gpxFile,
@NonNull String fileName, boolean forceImportFavourites) { @NonNull String fileName, boolean forceImportFavourites) {
super(activity); super(activity);
this.gpxFile = gpxFile; this.gpxFile = gpxFile;
this.fileName = fileName; this.fileName = fileName;

View file

@ -215,7 +215,7 @@ public class ImportHelper {
public static String getNameFromContentUri(OsmandApplication app, Uri contentUri) { public static String getNameFromContentUri(OsmandApplication app, Uri contentUri) {
try { try {
String name; String name;
Cursor returnCursor = app.getContentResolver().query(contentUri, new String[] {OpenableColumns.DISPLAY_NAME}, null, null, null); Cursor returnCursor = app.getContentResolver().query(contentUri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
if (returnCursor != null && returnCursor.moveToFirst()) { if (returnCursor != null && returnCursor.moveToFirst()) {
int columnIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); int columnIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (columnIndex != -1) { if (columnIndex != -1) {
@ -690,7 +690,7 @@ public class ImportHelper {
} else { } else {
fpCat = p.category; fpCat = p.category;
} }
FavouritePoint point = new FavouritePoint(p.lat, p.lon, p.name, fpCat); FavouritePoint point = new FavouritePoint(p.lat, p.lon, p.name, fpCat, p.ele, 0);
if (p.desc != null) { if (p.desc != null) {
point.setDescription(p.desc); point.setDescription(p.desc);
} }

View file

@ -1036,6 +1036,8 @@ public class MapContextMenu extends MenuTitleController implements StateChangedL
title = ""; title = "";
} }
String originObjectName = ""; String originObjectName = "";
double altitude = 0;
long timestamp = System.currentTimeMillis();
Object object = getObject(); Object object = getObject();
if (object != null) { if (object != null) {
if (object instanceof Amenity) { if (object instanceof Amenity) {
@ -1043,10 +1045,13 @@ public class MapContextMenu extends MenuTitleController implements StateChangedL
} else if (object instanceof TransportStop) { } else if (object instanceof TransportStop) {
originObjectName = ((TransportStop) object).toStringEn(); originObjectName = ((TransportStop) object).toStringEn();
} }
if (object instanceof WptPt) {
altitude = ((WptPt) object).ele;
}
} }
FavoritePointEditor favoritePointEditor = getFavoritePointEditor(); FavoritePointEditor favoritePointEditor = getFavoritePointEditor();
if (favoritePointEditor != null) { if (favoritePointEditor != null) {
favoritePointEditor.add(getLatLon(), title, getStreetStr(), originObjectName); favoritePointEditor.add(getLatLon(), title, getStreetStr(), originObjectName, altitude, timestamp);
} }
} }
}); });
@ -1074,7 +1079,8 @@ public class MapContextMenu extends MenuTitleController implements StateChangedL
for (OsmandMapLayer layer : mapActivity.getMapView().getLayers()) { for (OsmandMapLayer layer : mapActivity.getMapView().getLayers()) {
layer.populateObjectContextMenu(latLon, getObject(), menuAdapter, mapActivity); layer.populateObjectContextMenu(latLon, getObject(), menuAdapter, mapActivity);
} }
mapActivity.getMapActions().addActionsToAdapter(configure ? 0 : latLon.getLatitude(), configure ? 0 : latLon.getLongitude(), menuAdapter, configure ? null : getObject(), configure); } mapActivity.getMapActions().addActionsToAdapter(configure ? 0 : latLon.getLatitude(), configure ? 0 : latLon.getLongitude(), menuAdapter, configure ? null : getObject(), configure);
}
return menuAdapter; return menuAdapter;
} }

View file

@ -27,7 +27,7 @@ public class FavoritePointEditor extends PointEditor {
return favorite; return favorite;
} }
public void add(LatLon latLon, String title, String address, String originObjectName) { public void add(LatLon latLon, String title, String address, String originObjectName, double altitude, long timestamp) {
MapActivity mapActivity = getMapActivity(); MapActivity mapActivity = getMapActivity();
if (latLon == null || mapActivity == null) { if (latLon == null || mapActivity == null) {
return; return;
@ -37,7 +37,7 @@ public class FavoritePointEditor extends PointEditor {
if (!Algorithms.isEmpty(lastCategory) && !app.getFavorites().groupExists(lastCategory)) { if (!Algorithms.isEmpty(lastCategory) && !app.getFavorites().groupExists(lastCategory)) {
lastCategory = ""; lastCategory = "";
} }
favorite = new FavouritePoint(latLon.getLatitude(), latLon.getLongitude(), title, lastCategory); favorite = new FavouritePoint(latLon.getLatitude(), latLon.getLongitude(), title, lastCategory, altitude, timestamp);
favorite.setDescription(""); favorite.setDescription("");
favorite.setAddress(address.isEmpty() ? title : address); favorite.setAddress(address.isEmpty() ? title : address);
favorite.setOriginObjectName(originObjectName); favorite.setOriginObjectName(originObjectName);
@ -64,7 +64,6 @@ public class FavoritePointEditor extends PointEditor {
favorite.setDescription(""); favorite.setDescription("");
favorite.setAddress(""); favorite.setAddress("");
favorite.setOriginObjectName(originObjectName); favorite.setOriginObjectName(originObjectName);
FavoritePointEditorFragmentNew.showAutoFillInstance(mapActivity, autoFill); FavoritePointEditorFragmentNew.showAutoFillInstance(mapActivity, autoFill);
} }

View file

@ -190,7 +190,7 @@ public class FavoritePointEditorFragment extends PointEditorFragment {
final FavouritePoint favorite = getFavorite(); final FavouritePoint favorite = getFavorite();
if (favorite != null) { if (favorite != null) {
final FavouritePoint point = new FavouritePoint(favorite.getLatitude(), favorite.getLongitude(), final FavouritePoint point = new FavouritePoint(favorite.getLatitude(), favorite.getLongitude(),
getNameTextValue(), getCategoryTextValue()); getNameTextValue(), getCategoryTextValue(), favorite.getAltitude(), favorite.getTimestamp());
point.setDescription(getDescriptionTextValue()); point.setDescription(getDescriptionTextValue());
point.setAddress(getAddressTextValue()); point.setAddress(getAddressTextValue());
AlertDialog.Builder builder = FavouritesDbHelper.checkDuplicates(point, helper, getMapActivity()); AlertDialog.Builder builder = FavouritesDbHelper.checkDuplicates(point, helper, getMapActivity());
@ -198,7 +198,7 @@ public class FavoritePointEditorFragment extends PointEditorFragment {
if (favorite.getName().equals(point.getName()) && if (favorite.getName().equals(point.getName()) &&
favorite.getCategory().equals(point.getCategory()) && favorite.getCategory().equals(point.getCategory()) &&
Algorithms.stringsEqual(favorite.getDescription(), point.getDescription()) && Algorithms.stringsEqual(favorite.getDescription(), point.getDescription()) &&
Algorithms.stringsEqual(favorite.getAddress(),point.getAddress())) { Algorithms.stringsEqual(favorite.getAddress(), point.getAddress())) {
if (needDismiss) { if (needDismiss) {
dismiss(false); dismiss(false);
} }
@ -209,7 +209,7 @@ public class FavoritePointEditorFragment extends PointEditorFragment {
builder.setPositiveButton(R.string.shared_string_ok, new DialogInterface.OnClickListener() { builder.setPositiveButton(R.string.shared_string_ok, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
doSave(favorite, point.getName(), point.getCategory(), point.getDescription(),point.getAddress(), needDismiss); doSave(favorite, point.getName(), point.getCategory(), point.getDescription(), point.getAddress(), needDismiss);
} }
}); });
builder.create().show(); builder.create().show();
@ -225,9 +225,9 @@ public class FavoritePointEditorFragment extends PointEditorFragment {
FavoritePointEditor editor = getFavoritePointEditor(); FavoritePointEditor editor = getFavoritePointEditor();
if (editor != null && helper != null) { if (editor != null && helper != null) {
if (editor.isNew()) { if (editor.isNew()) {
doAddFavorite(name, category, description,address); doAddFavorite(name, category, description, address);
} else { } else {
helper.editFavouriteName(favorite, name, category, description,address); helper.editFavouriteName(favorite, name, category, description, address);
} }
} }
MapActivity mapActivity = getMapActivity(); MapActivity mapActivity = getMapActivity();

View file

@ -251,7 +251,7 @@ public class FavoritePointEditorFragmentNew extends PointEditorFragmentNew {
final FavouritePoint favorite = getFavorite(); final FavouritePoint favorite = getFavorite();
if (favorite != null) { if (favorite != null) {
final FavouritePoint point = new FavouritePoint(favorite.getLatitude(), favorite.getLongitude(), final FavouritePoint point = new FavouritePoint(favorite.getLatitude(), favorite.getLongitude(),
getNameTextValue(), getCategoryTextValue()); getNameTextValue(), getCategoryTextValue(), favorite.getAltitude(), favorite.getTimestamp());
point.setDescription(isDescriptionAvailable() ? getDescriptionTextValue() : null); point.setDescription(isDescriptionAvailable() ? getDescriptionTextValue() : null);
point.setAddress(isAddressAvailable() ? getAddressTextValue() : null); point.setAddress(isAddressAvailable() ? getAddressTextValue() : null);
point.setColor(color); point.setColor(color);
@ -267,7 +267,7 @@ public class FavoritePointEditorFragmentNew extends PointEditorFragmentNew {
final FavouritePoint favorite = getFavorite(); final FavouritePoint favorite = getFavorite();
if (favorite != null) { if (favorite != null) {
final FavouritePoint point = new FavouritePoint(favorite.getLatitude(), favorite.getLongitude(), final FavouritePoint point = new FavouritePoint(favorite.getLatitude(), favorite.getLongitude(),
getNameTextValue(), getCategoryTextValue()); getNameTextValue(), getCategoryTextValue(), favorite.getAltitude(), favorite.getTimestamp());
point.setDescription(isDescriptionAvailable() ? getDescriptionTextValue() : null); point.setDescription(isDescriptionAvailable() ? getDescriptionTextValue() : null);
point.setAddress(isAddressAvailable() ? getAddressTextValue() : null); point.setAddress(isAddressAvailable() ? getAddressTextValue() : null);
point.setColor(color); point.setColor(color);
@ -311,7 +311,7 @@ public class FavoritePointEditorFragmentNew extends PointEditorFragmentNew {
} }
private void doSave(FavouritePoint favorite, String name, String category, String description, String address, private void doSave(FavouritePoint favorite, String name, String category, String description, String address,
@ColorInt int color, BackgroundType backgroundType, @DrawableRes int iconId, boolean needDismiss) { @ColorInt int color, BackgroundType backgroundType, @DrawableRes int iconId, boolean needDismiss) {
FavouritesDbHelper helper = getHelper(); FavouritesDbHelper helper = getHelper();
FavoritePointEditor editor = getFavoritePointEditor(); FavoritePointEditor editor = getFavoritePointEditor();
if (editor != null && helper != null) { if (editor != null && helper != null) {
@ -338,8 +338,8 @@ public class FavoritePointEditorFragmentNew extends PointEditorFragmentNew {
} }
private void doEditFavorite(FavouritePoint favorite, String name, String category, String description, String address, private void doEditFavorite(FavouritePoint favorite, String name, String category, String description, String address,
@ColorInt int color, BackgroundType backgroundType, @DrawableRes int iconId, @ColorInt int color, BackgroundType backgroundType, @DrawableRes int iconId,
FavouritesDbHelper helper) { FavouritesDbHelper helper) {
OsmandApplication app = getMyApplication(); OsmandApplication app = getMyApplication();
if (app != null) { if (app != null) {
app.getSettings().LAST_FAV_CATEGORY_ENTERED.set(category); app.getSettings().LAST_FAV_CATEGORY_ENTERED.set(category);
@ -351,7 +351,7 @@ public class FavoritePointEditorFragmentNew extends PointEditorFragmentNew {
} }
private void doAddFavorite(String name, String category, String description, String address, @ColorInt int color, private void doAddFavorite(String name, String category, String description, String address, @ColorInt int color,
BackgroundType backgroundType, @DrawableRes int iconId) { BackgroundType backgroundType, @DrawableRes int iconId) {
OsmandApplication app = getMyApplication(); OsmandApplication app = getMyApplication();
FavouritesDbHelper helper = getHelper(); FavouritesDbHelper helper = getHelper();
FavouritePoint favorite = getFavorite(); FavouritePoint favorite = getFavorite();