OsmAnd/OsmAnd-java/src/net/osmand/binary/RouteDataObject.java

816 lines
24 KiB
Java
Raw Normal View History

package net.osmand.binary;
import gnu.trove.map.hash.TIntObjectHashMap;
import java.text.MessageFormat;
import java.util.Arrays;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
2014-02-02 14:06:09 +01:00
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import net.osmand.Location;
import net.sf.junidecode.Junidecode;
public class RouteDataObject {
/*private */static final int RESTRICTION_SHIFT = 3;
/*private */static final int RESTRICTION_MASK = 7;
2017-02-08 09:54:38 +01:00
public static int HEIGHT_UNDEFINED = -80000;
public final RouteRegion region;
// all these arrays supposed to be immutable!
// These fields accessible from C++
public int[] types;
public int[] pointsX;
public int[] pointsY;
public long[] restrictions;
public int[][] pointTypes;
2015-07-06 07:08:10 +02:00
public String[][] pointNames;
public int[][] pointNameTypes;
public long id;
public TIntObjectHashMap<String> names;
public final static float NONE_MAX_SPEED = 40f;
public int[] nameIds;
2017-02-08 09:54:38 +01:00
// mixed array [0, height, cumulative_distance height, cumulative_distance, height, ...] - length is length(points)*2
public float[] heightDistanceArray = null;
public RouteDataObject(RouteRegion region) {
this.region = region;
}
public RouteDataObject(RouteRegion region, int[] nameIds, String[] nameValues) {
this.region = region;
this.nameIds = nameIds;
if (nameIds.length > 0) {
names = new TIntObjectHashMap<String>();
}
for (int i = 0; i < nameIds.length; i++) {
names.put(nameIds[i], nameValues[i]);
}
}
public RouteDataObject(RouteDataObject copy) {
this.region = copy.region;
this.pointsX = copy.pointsX;
this.pointsY = copy.pointsY;
this.types = copy.types;
this.names = copy.names;
this.restrictions = copy.restrictions;
this.pointTypes = copy.pointTypes;
2015-07-06 07:08:10 +02:00
this.pointNames = copy.pointNames;
this.pointNameTypes = copy.pointNameTypes;
this.id = copy.id;
}
2017-02-08 09:54:38 +01:00
public boolean compareRoute(RouteDataObject thatObj) {
if (this.id == thatObj.id
&& Arrays.equals(this.pointsX, thatObj.pointsX)
2017-08-30 18:06:55 +02:00
&& Arrays.equals(this.pointsY, thatObj.pointsY)) {
if (this.region == null) {
throw new IllegalStateException("Illegal routing object: " + id);
}
if (thatObj.region == null) {
throw new IllegalStateException("Illegal routing object: " + thatObj.id);
}
2017-08-30 18:06:55 +02:00
boolean equals = true;
2017-08-30 18:06:55 +02:00
equals = equals && Arrays.equals(this.restrictions, thatObj.restrictions);
2017-09-02 22:08:38 +02:00
if (equals) {
if (this.types == null || thatObj.types == null) {
equals = this.types == thatObj.types;
} else if (types.length != thatObj.types.length) {
equals = false;
} else {
for (int i = 0; i < this.types.length && equals; i++) {
String thisTag = region.routeEncodingRules.get(types[i]).getTag();
String thisValue = region.routeEncodingRules.get(types[i]).getValue();
String thatTag = thatObj.region.routeEncodingRules.get(thatObj.types[i]).getTag();
String thatValue = thatObj.region.routeEncodingRules.get(thatObj.types[i]).getValue();
equals = (thisTag.equals(thatTag) && thisValue.equals(thatValue));
}
}
}
2017-08-30 18:06:55 +02:00
if (equals) {
if (this.nameIds == null || thatObj.nameIds == null) {
equals = this.nameIds == thatObj.nameIds;
} else if (nameIds.length != thatObj.nameIds.length) {
equals = false;
} else {
for (int i = 0; i < this.nameIds.length && equals; i++) {
String thisTag = region.routeEncodingRules.get(nameIds[i]).getTag();
String thisValue = names.get(nameIds[i]);
String thatTag = thatObj.region.routeEncodingRules.get(thatObj.nameIds[i]).getTag();
String thatValue = thatObj.names.get(thatObj.nameIds[i]);
equals = (Algorithms.objectEquals(thisTag, thatTag) && Algorithms.objectEquals(thisValue, thatValue));
}
}
}
2017-08-30 22:35:41 +02:00
if (equals) {
if (this.pointTypes == null || thatObj.pointTypes == null) {
equals = this.pointTypes == thatObj.pointTypes;
} else if (pointTypes.length != thatObj.pointTypes.length) {
equals = false;
} else {
for (int i = 0; i < this.pointTypes.length && equals; i++) {
if (this.pointTypes[i] == null || thatObj.pointTypes[i] == null) {
equals = this.pointTypes[i] == thatObj.pointTypes[i];
} else if (pointTypes[i].length != thatObj.pointTypes[i].length) {
equals = false;
} else {
for (int j = 0; j < this.pointTypes[i].length && equals; j++) {
String thisTag = region.routeEncodingRules.get(pointTypes[i][j]).getTag();
String thisValue = region.routeEncodingRules.get(pointTypes[i][j]).getValue();
String thatTag = thatObj.region.routeEncodingRules.get(thatObj.pointTypes[i][j]).getTag();
String thatValue = thatObj.region.routeEncodingRules.get(thatObj.pointTypes[i][j]).getValue();
equals = (Algorithms.objectEquals(thisTag, thatTag) && Algorithms.objectEquals(thisValue, thatValue));
}
}
}
}
}
2017-08-30 18:06:55 +02:00
if (equals) {
if (this.pointNameTypes == null || thatObj.pointNameTypes == null) {
equals = this.pointNameTypes == thatObj.pointNameTypes;
} else if (pointNameTypes.length != thatObj.pointNameTypes.length) {
equals = false;
} else {
for (int i = 0; i < this.pointNameTypes.length && equals; i++) {
if (this.pointNameTypes[i] == null || thatObj.pointNameTypes[i] == null) {
equals = this.pointNameTypes[i] == thatObj.pointNameTypes[i];
} else if (pointNameTypes[i].length != thatObj.pointNameTypes[i].length) {
equals = false;
} else {
for (int j = 0; j < this.pointNameTypes[i].length && equals; j++) {
String thisTag = region.routeEncodingRules.get(pointNameTypes[i][j]).getTag();
String thisValue = pointNames[i][j];
String thatTag = thatObj.region.routeEncodingRules.get(thatObj.pointNameTypes[i][j]).getTag();
String thatValue = thatObj.pointNames[i][j];
equals = (Algorithms.objectEquals(thisTag, thatTag) && Algorithms.objectEquals(thisValue, thatValue));
}
}
}
}
}
2017-09-02 22:08:38 +02:00
return equals;
}
return false;
}
2017-02-08 09:54:38 +01:00
public float[] calculateHeightArray() {
if(heightDistanceArray != null) {
return heightDistanceArray;
}
int startHeight = Algorithms.parseIntSilently(getValue("osmand_ele_start"), HEIGHT_UNDEFINED);
int endHeight = Algorithms.parseIntSilently(getValue("osmand_ele_end"), startHeight);
if(startHeight == HEIGHT_UNDEFINED) {
heightDistanceArray = new float[0];
return heightDistanceArray;
}
heightDistanceArray = new float[2*getPointsLength()];
double plon = 0;
double plat = 0;
float prevHeight = startHeight;
2017-02-08 09:54:38 +01:00
for(int k = 0; k < getPointsLength(); k++) {
double lon = MapUtils.get31LongitudeX(getPoint31XTile(k));
double lat = MapUtils.get31LatitudeY(getPoint31YTile(k));
if(k > 0) {
double dd = MapUtils.getDistance(plat, plon, lat, lon);
float height = HEIGHT_UNDEFINED;
2017-02-08 09:54:38 +01:00
if(k == getPointsLength() - 1) {
height = endHeight;
} else {
int[] tps = getPointTypes(k);
if (tps != null) {
for (int id : tps) {
RouteTypeRule rt = region.quickGetEncodingRule(id);
if (rt.getTag().equals("osmand_ele_asc")) {
height = (prevHeight + Float.parseFloat(rt.getValue()));
2017-02-08 09:54:38 +01:00
break;
} else if (rt.getTag().equals("osmand_ele_desc")) {
height = (prevHeight - Float.parseFloat(rt.getValue()));
2017-02-08 09:54:38 +01:00
break;
}
}
}
}
heightDistanceArray[2*k] = (float) dd;
heightDistanceArray[2*k+1] = height;
if(height != HEIGHT_UNDEFINED) {
// interpolate undefined
double totalDistance = dd;
int startUndefined = k;
while(startUndefined - 1 >= 0 && heightDistanceArray[2*(startUndefined - 1)+1] == HEIGHT_UNDEFINED) {
startUndefined --;
totalDistance += heightDistanceArray[2*(startUndefined)];
}
if(totalDistance > 0) {
double angle = (height - prevHeight) / totalDistance;
for(int j = startUndefined; j < k; j++) {
heightDistanceArray[2*j+1] = (float) ((heightDistanceArray[2*j] * angle) + heightDistanceArray[2*j-1]);
}
}
prevHeight = height;
}
} else {
heightDistanceArray[0] = 0;
heightDistanceArray[1] = startHeight;
}
plat = lat;
plon = lon;
}
return heightDistanceArray;
}
public long getId() {
return id;
}
public String getName(){
if(names != null ) {
return names.get(region.nameTypeRule);
}
return null;
}
public String getName(String lang){
return getName(lang, false);
}
public String getName(String lang, boolean transliterate){
if(names != null ) {
if(Algorithms.isEmpty(lang)) {
return names.get(region.nameTypeRule);
}
int[] kt = names.keys();
for(int i = 0 ; i < kt.length; i++) {
int k = kt[i];
if(region.routeEncodingRules.size() > k) {
if(("name:"+lang).equals(region.routeEncodingRules.get(k).getTag())) {
return names.get(k);
}
}
}
String nmDef = names.get(region.nameTypeRule);
if(transliterate && nmDef != null && nmDef.length() > 0) {
return Junidecode.unidecode(nmDef);
}
return nmDef;
}
return null;
}
public int[] getNameIds() {
return nameIds;
}
public TIntObjectHashMap<String> getNames() {
return names;
}
public String getRef(String lang, boolean transliterate, boolean direction) {
//if (getDestinationRef(direction) != null) {
2016-12-02 14:54:11 +01:00
// return getDestinationRef(direction);
//}
if (names != null) {
if(Algorithms.isEmpty(lang)) {
return names.get(region.refTypeRule);
}
int[] kt = names.keys();
for(int i = 0 ; i < kt.length; i++) {
int k = kt[i];
if(region.routeEncodingRules.size() > k) {
if(("ref:"+lang).equals(region.routeEncodingRules.get(k).getTag())) {
return names.get(k);
}
}
}
String refDefault = names.get(region.refTypeRule);
if(transliterate && refDefault != null && refDefault.length() > 0) {
return Junidecode.unidecode(refDefault);
}
return refDefault;
}
return null;
}
public String getDestinationRef(boolean direction) {
2014-12-10 00:27:03 +01:00
if (names != null) {
int[] kt = names.keys();
String refTag = (direction == true) ? "destination:ref:forward" : "destination:ref:backward";
2016-08-19 19:33:36 +02:00
String refTagDefault = "destination:ref";
String refDefault = null;
for(int i = 0 ; i < kt.length; i++) {
int k = kt[i];
if(region.routeEncodingRules.size() > k) {
if(refTag.equals(region.routeEncodingRules.get(k).getTag())) {
return names.get(k);
}
2016-08-19 19:33:36 +02:00
if(refTagDefault.equals(region.routeEncodingRules.get(k).getTag())) {
refDefault = names.get(k);
}
}
}
2016-08-19 19:42:09 +02:00
if (refDefault != null) {
2016-08-19 19:33:36 +02:00
return refDefault;
2014-12-10 00:27:03 +01:00
}
//return names.get(region.refTypeRule);
}
return null;
}
public String getDestinationName(String lang, boolean transliterate, boolean direction){
//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);
2016-12-02 15:06:39 +01:00
String destRef1 = ("".equals(destRef)) ? "" : destRef + ", ";
2014-12-10 00:27:03 +01:00
if(names != null) {
int[] kt = names.keys();
2016-10-31 09:12:56 +01:00
// Issue #3181: Parse destination keys in this order:
// destination:lang:XX:forward/backward
// destination:forward/backward
// destination:lang:XX
2016-10-26 21:09:26 +02:00
// destination
String destinationTagLangFB = "destination:lang:XX";
if(!Algorithms.isEmpty(lang)) {
destinationTagLangFB = (direction == true) ? "destination:lang:" + lang + ":forward" : "destination:lang:" + lang + ":backward";
}
String destinationTagFB = (direction == true) ? "destination:forward" : "destination:backward";
String destinationTagLang = "destination:lang:XX";
if(!Algorithms.isEmpty(lang)) {
2016-10-26 10:33:14 +02:00
destinationTagLang = "destination:lang:" + lang;
}
2016-08-19 19:33:36 +02:00
String destinationTagDefault = "destination";
String destinationDefault = null;
for(int i = 0 ; i < kt.length; i++) {
int k = kt[i];
if(region.routeEncodingRules.size() > k) {
if(!Algorithms.isEmpty(lang) && destinationTagLangFB.equals(region.routeEncodingRules.get(k).getTag())) {
2016-12-02 15:06:39 +01:00
return destRef1 + ((transliterate) ? Junidecode.unidecode(names.get(k)) : names.get(k));
}
if(destinationTagFB.equals(region.routeEncodingRules.get(k).getTag())) {
2016-12-02 15:06:39 +01:00
return destRef1 + ((transliterate) ? Junidecode.unidecode(names.get(k)) : names.get(k));
}
if(!Algorithms.isEmpty(lang) && destinationTagLang.equals(region.routeEncodingRules.get(k).getTag())) {
2016-12-02 15:06:39 +01:00
return destRef1 + ((transliterate) ? Junidecode.unidecode(names.get(k)) : names.get(k));
}
2016-08-19 19:33:36 +02:00
if(destinationTagDefault.equals(region.routeEncodingRules.get(k).getTag())) {
destinationDefault = names.get(k);
}
}
}
2016-12-04 11:47:20 +01:00
if(destinationDefault != null) {
return destRef1 + ((transliterate) ? Junidecode.unidecode(destinationDefault) : destinationDefault);
}
}
return "".equals(destRef) ? null : destRef;
}
public int getPoint31XTile(int i) {
return pointsX[i];
}
public int getPoint31YTile(int i) {
return pointsY[i];
}
public int getPointsLength() {
return pointsX.length;
}
public int getRestrictionLength() {
return restrictions == null ? 0 : restrictions.length;
}
public int getRestrictionType(int i) {
return (int) (restrictions[i] & RESTRICTION_MASK);
}
2017-09-02 18:54:57 +02:00
public long getRawRestriction(int i) {
return restrictions[i];
}
public long getRestrictionId(int i) {
return restrictions[i] >> RESTRICTION_SHIFT;
}
2016-04-26 20:08:37 +02:00
public boolean hasPointTypes() {
return pointTypes != null;
}
public boolean hasPointNames() {
return pointNames != null;
}
public void insert(int pos, int x31, int y31) {
int[] opointsX = pointsX;
int[] opointsY = pointsY;
int[][] opointTypes = pointTypes;
pointsX = new int[pointsX.length + 1];
pointsY = new int[pointsY.length + 1];
boolean insTypes = this.pointTypes != null && this.pointTypes.length > pos;
if (insTypes) {
pointTypes = new int[opointTypes.length + 1][];
}
int i = 0;
for (; i < pos; i++) {
pointsX[i] = opointsX[i];
pointsY[i] = opointsY[i];
if (insTypes) {
pointTypes[i] = opointTypes[i];
}
}
pointsX[i] = x31;
pointsY[i] = y31;
if (insTypes) {
pointTypes[i] = null;
}
for (i = i + 1; i < pointsX.length; i++) {
pointsX[i] = opointsX[i - 1];
pointsY[i] = opointsY[i - 1];
if (insTypes && i < pointTypes.length) {
pointTypes[i] = opointTypes[i - 1];
}
}
}
2015-07-06 07:08:10 +02:00
public String[] getPointNames(int ind) {
if (pointNames == null || ind >= pointNames.length) {
return null;
}
return pointNames[ind];
}
public int[] getPointNameTypes(int ind) {
if (pointNameTypes == null || ind >= pointNameTypes.length) {
return null;
}
return pointNameTypes[ind];
}
public int[] getPointTypes(int ind) {
if (pointTypes == null || ind >= pointTypes.length) {
return null;
}
return pointTypes[ind];
}
public int[] getTypes() {
return types;
}
2016-08-19 14:37:15 +02:00
2015-08-31 00:11:48 +02:00
public float getMaximumSpeed(boolean direction){
int sz = types.length;
2016-08-19 14:37:15 +02:00
float maxSpeed = 0;
for (int i = 0; i < sz; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
2015-08-31 00:11:48 +02:00
if(r.isForward() != 0) {
2016-10-25 12:55:21 +02:00
if((r.isForward() == 1) != direction) {
2015-08-31 00:11:48 +02:00
continue;
}
}
2016-08-19 14:37:15 +02:00
float mx = r.maxSpeed();
if (mx > 0) {
maxSpeed = mx;
// conditional has priority
if(r.conditional()) {
break;
}
}
}
2013-09-12 01:24:09 +02:00
return maxSpeed ;
}
2016-08-19 14:37:15 +02:00
2014-02-02 14:06:09 +01:00
public static float parseSpeed(String v, float def) {
if(v.equals("none")) {
return RouteDataObject.NONE_MAX_SPEED;
} else {
int i = Algorithms.findFirstNumberEndIndex(v);
if (i > 0) {
float f = Float.parseFloat(v.substring(0, i));
f /= 3.6; // km/h -> m/s
if (v.contains("mph")) {
f *= 1.6;
}
return f;
}
}
return def;
}
public static float parseLength(String v, float def) {
2015-05-09 23:53:16 +02:00
float f = 0;
// 14'10" 14 - inches, 10 feet
2014-02-02 14:06:09 +01:00
int i = Algorithms.findFirstNumberEndIndex(v);
if (i > 0) {
2015-05-09 23:53:16 +02:00
f += Float.parseFloat(v.substring(0, i));
String pref = v.substring(i, v.length()).trim();
float add = 0;
for(int ik = 0; ik < pref.length(); ik++) {
2015-08-04 10:51:46 +02:00
if(Algorithms.isDigit(pref.charAt(ik)) || pref.charAt(ik) == '.' || pref.charAt(ik) == '-') {
2015-05-09 23:53:16 +02:00
int first = Algorithms.findFirstNumberEndIndex(pref.substring(ik));
if(first != -1) {
add = parseLength(pref.substring(ik), 0);
pref = pref.substring(0, ik);
}
2015-05-09 23:53:16 +02:00
break;
}
2014-02-02 14:06:09 +01:00
}
2015-05-09 23:53:16 +02:00
if(pref.contains("km")) {
f *= 1000;
}
2016-06-15 01:20:36 +02:00
if(pref.contains("\"") || pref.contains("in")) {
2015-05-09 23:53:16 +02:00
f *= 0.0254;
2016-06-15 01:20:36 +02:00
} else if (pref.contains("\'") || pref.contains("ft") || pref.contains("feet")) {
2015-05-09 23:53:16 +02:00
// foot to meters
f *= 0.3048;
2016-06-15 01:20:36 +02:00
} else if (pref.contains("cm")) {
f *= 0.01;
} else if (pref.contains("mile")) {
f *= 1609.34f;
2015-05-09 23:53:16 +02:00
}
return f + add;
2014-02-02 14:06:09 +01:00
}
return def;
}
public static float parseWeightInTon(String v, float def) {
int i = Algorithms.findFirstNumberEndIndex(v);
if (i > 0) {
float f = Float.parseFloat(v.substring(0, i));
if (v.contains("\"") || v.contains("lbs")) {
// lbs -> kg -> ton
f = (f * 0.4535f) / 1000f;
}
return f;
}
return def;
}
public boolean loop(){
return pointsX[0] == pointsX[pointsX.length - 1] && pointsY[0] == pointsY[pointsY.length - 1] ;
}
public boolean roundabout(){
int sz = types.length;
for(int i=0; i<sz; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
if(r.roundabout()) {
return true;
} else if(r.onewayDirection() != 0 && loop()) {
return true;
}
}
return false;
}
2013-10-29 21:13:57 +01:00
public boolean tunnel(){
int sz = types.length;
for(int i=0; i<sz; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
if(r.getTag().equals("tunnel") && r.getValue().equals("yes")) {
return true;
}
if(r.getTag().equals("layer") && r.getValue().equals("-1")) {
return true;
}
}
return false;
}
public int getOneway() {
int sz = types.length;
for (int i = 0; i < sz; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
if (r.onewayDirection() != 0) {
return r.onewayDirection();
} else if (r.roundabout()) {
return 1;
}
}
return 0;
}
public String getRoute() {
int sz = types.length;
for (int i = 0; i < sz; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
if ("route".equals(r.getTag())) {
return r.getValue();
}
}
return null;
}
public String getHighway() {
return getHighway(types, region);
}
2014-10-02 14:14:34 +02:00
2017-04-11 17:28:58 +02:00
public boolean hasPrivateAccess() {
int sz = types.length;
for (int i = 0; i < sz; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
if ("motorcar".equals(r.getTag())
|| "motor_vehicle".equals(r.getTag())
|| "vehicle".equals(r.getTag())
|| "access".equals(r.getTag())) {
if (r.getValue().equals("private")) {
return true;
}
}
}
return false;
}
2014-10-02 14:14:34 +02:00
public String getValue(String tag) {
for (int i = 0; i < types.length; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
if (r.getTag().equals(tag)) {
return r.getValue();
}
}
return null;
}
public static String getHighway(int[] types, RouteRegion region) {
String highway = null;
int sz = types.length;
for (int i = 0; i < sz; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
highway = r.highwayRoad();
if (highway != null) {
break;
}
}
return highway;
}
public int getLanes() {
int sz = types.length;
for (int i = 0; i < sz; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
int ln = r.lanes();
if (ln > 0) {
return ln;
}
}
return -1;
}
public double directionRoute(int startPoint, boolean plus) {
// same goes to C++
// Victor : the problem to put more than 5 meters that BinaryRoutePlanner will treat
// 2 consequent Turn Right as UT and here 2 points will have same turn angle
// So it should be fix in both places
return directionRoute(startPoint, plus, 5);
}
public boolean bearingVsRouteDirection(Location loc) {
boolean direction = true;
if(loc != null && loc.hasBearing()) {
double diff = MapUtils.alignAngleDifference(directionRoute(0, true) - loc.getBearing() / 180f * Math.PI);
direction = Math.abs(diff) < Math.PI / 2f;
}
return direction;
}
2017-10-27 15:36:42 +02:00
public int isStopForward(boolean direction) {
for (int i = 0; i < types.length; i++) {
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
if (r.getTag().equals("highway") && r.getValue().equals("stop")) {
2017-10-27 15:36:42 +02:00
for (int j = 0; j < types.length; j++) {
if (r.getTag().equals("direction")) {
2017-10-27 15:56:19 +02:00
String dv = r.getValue();
2017-10-27 16:19:35 +02:00
if ((dv.equals("forward") && direction == true) || (dv.equals("backward") && direction == false)) {
2017-10-27 15:36:42 +02:00
return 1;
2017-10-27 16:19:35 +02:00
} else if ((dv.equals("forward") && direction == false) || (dv.equals("backward") && direction == true)) {
2017-10-27 15:36:42 +02:00
return -1;
}
}
2017-10-27 15:36:42 +02:00
// stop=all usually tagged on conflicting node itself, so not needed here
//if (r.getTag().equals("stop") && r.getValue().equals("all")) {
// return 1;
//}
}
}
}
2017-10-27 15:36:42 +02:00
return 0; //no directional info detected
}
2013-11-26 16:23:05 +01:00
public double distance(int startPoint, int endPoint) {
if(startPoint > endPoint) {
int k = endPoint;
endPoint = startPoint;
startPoint = k;
}
double d = 0;
for(int k = startPoint; k < endPoint && k < getPointsLength() -1; k++) {
int x = getPoint31XTile(k);
int y = getPoint31YTile(k);
int kx = getPoint31XTile(k + 1);
int ky = getPoint31YTile(k + 1);
d += simplifyDistance(kx, ky, x, y);
}
return d;
}
// Gives route direction of EAST degrees from NORTH ]-PI, PI]
public double directionRoute(int startPoint, boolean plus, float dist) {
int x = getPoint31XTile(startPoint);
int y = getPoint31YTile(startPoint);
int nx = startPoint;
int px = x;
int py = y;
double total = 0;
do {
if (plus) {
nx++;
if (nx >= getPointsLength()) {
break;
}
} else {
nx--;
if (nx < 0) {
break;
}
}
px = getPoint31XTile(nx);
py = getPoint31YTile(nx);
// translate into meters
2013-11-26 16:23:05 +01:00
total += simplifyDistance(x, y, px, py);
} while (total < dist);
return -Math.atan2( x - px, y - py );
}
2013-11-26 16:23:05 +01:00
private double simplifyDistance(int x, int y, int px, int py) {
return Math.abs(px - x) * 0.011d + Math.abs(py - y) * 0.01863d;
}
2015-05-09 23:53:16 +02:00
private static void assertTrueLength(String vl, float exp){
float dest = parseLength(vl, 0);
if(exp != dest) {
System.err.println("FAIL " + vl + " " + dest);
} else {
System.out.println("OK " + vl);
}
}
public static void main(String[] args) {
assertTrueLength("10 km", 10000);
2016-06-15 01:20:36 +02:00
assertTrueLength("0.01 km", 10);
assertTrueLength("0.01 km 10 m", 20);
assertTrueLength("10 m", 10);
assertTrueLength("10m", 10);
assertTrueLength("3.4 m", 3.4f);
assertTrueLength("3.40 m", 3.4f);
assertTrueLength("10 m 10m", 20);
assertTrueLength("14'10\"", 4.5212f);
assertTrueLength("14.5'", 4.4196f);
assertTrueLength("14.5 ft", 4.4196f);
assertTrueLength("14'0\"", 4.2672f);
assertTrueLength("15ft", 4.572f);
assertTrueLength("15 ft 1 in", 4.5974f);
assertTrueLength("4.1 metres", 4.1f);
assertTrueLength("14'0''", 4.2672f);
assertTrueLength("14 feet", 4.2672f);
assertTrueLength("14 mile", 22530.76f);
assertTrueLength("14 cm", 0.14f);
// float badValue = -1;
// assertTrueLength("none", badValue);
// assertTrueLength("m 4.1", badValue);
// assertTrueLength("1F4 m", badValue);
2015-05-09 23:53:16 +02:00
}
public String coordinates() {
StringBuilder b = new StringBuilder();
b.append(" lat/lon : ");
for (int i = 0; i < getPointsLength(); i++) {
float x = (float) MapUtils.get31LongitudeX(getPoint31XTile(i));
float y = (float) MapUtils.get31LatitudeY(getPoint31YTile(i));
b.append(y).append(" / ").append(x).append(" , ");
}
return b.toString();
}
@Override
public String toString() {
String name = getName();
String rf = getRef("", false, true);
2016-06-15 00:59:00 +02:00
return MessageFormat.format("Road id {0} name {1} ref {2}", (getId() / 64) + "", name == null ? "" : name,
rf == null ? "" : rf);
}
}