diff --git a/OsmAnd-java/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java b/OsmAnd-java/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java index dcbebbf704..f17c426343 100644 --- a/OsmAnd-java/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java +++ b/OsmAnd-java/src/net/osmand/binary/BinaryMapRouteReaderAdapter.java @@ -217,6 +217,7 @@ public class BinaryMapRouteReaderAdapter { public String getPartName() { return "Routing"; } + public int getFieldNumber() { return OsmandOdb.OsmAndStructure.ROUTINGINDEX_FIELD_NUMBER; diff --git a/OsmAnd-java/src/net/osmand/binary/RouteDataObject.java b/OsmAnd-java/src/net/osmand/binary/RouteDataObject.java index 06d547a062..dddb23c7d7 100644 --- a/OsmAnd-java/src/net/osmand/binary/RouteDataObject.java +++ b/OsmAnd-java/src/net/osmand/binary/RouteDataObject.java @@ -16,6 +16,7 @@ import net.sf.junidecode.Junidecode; public class RouteDataObject { /*private */static final int RESTRICTION_SHIFT = 3; /*private */static final int RESTRICTION_MASK = 7; + public static int HEIGHT_UNDEFINED = -80000; public final RouteRegion region; // all these arrays supposed to be immutable! @@ -31,6 +32,8 @@ public class RouteDataObject { public TIntObjectHashMap names; public final static float NONE_MAX_SPEED = 40f; public int[] nameIds; + // 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; @@ -59,6 +62,73 @@ public class RouteDataObject { this.pointNameTypes = copy.pointNameTypes; this.id = copy.id; } + + 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; + int prevHeight = startHeight; + 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); + int height = HEIGHT_UNDEFINED; + 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 = (int) (prevHeight + Float.parseFloat(rt.getValue())); + break; + } else if (rt.getTag().equals("osmand_ele_desc")) { + height = (int) (prevHeight - Float.parseFloat(rt.getValue())); + 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; diff --git a/OsmAnd-java/src/net/osmand/router/BinaryRoutePlanner.java b/OsmAnd-java/src/net/osmand/router/BinaryRoutePlanner.java index b224139851..8871def3d7 100644 --- a/OsmAnd-java/src/net/osmand/router/BinaryRoutePlanner.java +++ b/OsmAnd-java/src/net/osmand/router/BinaryRoutePlanner.java @@ -445,10 +445,16 @@ public class BinaryRoutePlanner { if (obstacle < 0) { directionAllowed = false; continue; + } + double heightObstacle = ctx.getRouter().defineHeightObstacle(road, !reverseWaySearch ? prevInd : segmentPoint, + !reverseWaySearch ? segmentPoint : prevInd, segmentDist); + if(heightObstacle > 0) { + } boolean alreadyVisited = checkIfOppositeSegmentWasVisited(ctx, reverseWaySearch, graphSegments, segment, oppositeSegments, segmentPoint, segmentDist, obstaclesTime); obstaclesTime += obstacle; + obstaclesTime += heightObstacle; if (alreadyVisited) { directionAllowed = false; continue; diff --git a/OsmAnd-java/src/net/osmand/router/GeneralRouter.java b/OsmAnd-java/src/net/osmand/router/GeneralRouter.java index a497b57c9d..a49702f758 100644 --- a/OsmAnd-java/src/net/osmand/router/GeneralRouter.java +++ b/OsmAnd-java/src/net/osmand/router/GeneralRouter.java @@ -25,6 +25,7 @@ public class GeneralRouter implements VehicleRouter { private static final float CAR_SHORTEST_DEFAULT_SPEED = 55/3.6f; public static final String USE_SHORTEST_WAY = "short_way"; + public static final String USE_HEIGHT_OBSTACLES = "height_obstacles"; public static final String AVOID_FERRIES = "avoid_ferries"; public static final String AVOID_TOLL = "avoid_toll"; public static final String AVOID_MOTORWAY = "avoid_motorway"; @@ -39,6 +40,7 @@ public class GeneralRouter implements VehicleRouter { private final Map tagRuleMask; private final ArrayList ruleToValue; private boolean shortestRoute; + private boolean heightObstacles; private Map> regionConvert = new LinkedHashMap>(); @@ -129,6 +131,7 @@ public class GeneralRouter implements VehicleRouter { objectAttributes[i] = new RouteAttributeContext(parent.objectAttributes[i], params); } shortestRoute = params.containsKey(USE_SHORTEST_WAY) && parseSilentBoolean(params.get(USE_SHORTEST_WAY), false); + heightObstacles = params.containsKey(USE_HEIGHT_OBSTACLES) && parseSilentBoolean(params.get(USE_HEIGHT_OBSTACLES), false); if(shortestRoute) { maxDefaultSpeed = Math.min(CAR_SHORTEST_DEFAULT_SPEED, maxDefaultSpeed); } @@ -284,6 +287,39 @@ public class GeneralRouter implements VehicleRouter { return 0; } + @Override + public double defineHeightObstacle(RouteDataObject road, short startIndex, short endIndex, float distance) { + if(!heightObstacles) { + return 0; + } + float[] heightArray = road.calculateHeightArray(); + if(heightArray == null || heightArray.length == 0 ) { + return 0; + } + + double sum = 0; + int knext; + int[] types = new int[0]; + RouteAttributeContext objContext = getObjContext(RouteDataObjectAttribute.OBSTACLE_SRTM_ALT_SPEED); + for(int k = startIndex; k != endIndex; k = knext) { + knext = startIndex < endIndex ? k + 1 : k - 1; + double dist = Math.abs(heightArray[2 * k] - heightArray[2 * knext]) ; + double diff = heightArray[2 * knext + 1] - heightArray[2 * k + 1] ; + if(diff > 0 && dist > 0) { + double incl = diff / dist; + int percentIncl = (int) (incl * 100); + percentIncl = (percentIncl + 2)/ 3 * 3 - 2; // 1, 4, 7, 10, . + if(percentIncl > 0) { + // IMPROVEMENT: register with value and cache parsed value + objContext.paramContext.vars.put("incline", percentIncl + ""); + sum += objContext.evaluateFloat(road.region, types, 0) * diff; + } + } + } + return sum; + } + + @Override public int isOneWay(RouteDataObject road) { return getObjContext(RouteDataObjectAttribute.ONEWAY).evaluateInt(road, 0); @@ -299,6 +335,7 @@ public class GeneralRouter implements VehicleRouter { return Math.min(defineVehicleSpeed(road), maxDefaultSpeed); } + @Override public float defineVehicleSpeed(RouteDataObject road) { return getObjContext(RouteDataObjectAttribute.ROAD_SPEED) .evaluateFloat(road, getMinDefaultSpeed()); diff --git a/OsmAnd-java/src/net/osmand/router/RouteSegmentResult.java b/OsmAnd-java/src/net/osmand/router/RouteSegmentResult.java index 747284db4c..9be9f387de 100644 --- a/OsmAnd-java/src/net/osmand/router/RouteSegmentResult.java +++ b/OsmAnd-java/src/net/osmand/router/RouteSegmentResult.java @@ -1,8 +1,6 @@ package net.osmand.router; -import gnu.trove.list.array.TIntArrayList; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -27,7 +25,6 @@ public class RouteSegmentResult { private String description = ""; // this make not possible to make turns in between segment result for now private TurnType turnType; - public static int HEIGHT_UNDEFINED = -80000; public RouteSegmentResult(RouteDataObject object, int startPointIndex, int endPointIndex) { @@ -38,70 +35,13 @@ public class RouteSegmentResult { } public float[] getHeightValues() { - int startHeight = Algorithms.parseIntSilently(object.getValue("osmand_ele_start"), HEIGHT_UNDEFINED); - int endHeight = Algorithms.parseIntSilently(object.getValue("osmand_ele_end"), startHeight); - if(startHeight == HEIGHT_UNDEFINED) { + float[] pf = object.calculateHeightArray(); + if(pf == null || pf.length == 0) { return new float[0]; } - TIntArrayList list = new TIntArrayList(); - float[] pf = new float[2*object.getPointsLength()]; - double dist = 0; - double plon = 0; - double plat = 0; - int prevHeight = startHeight; - for(int k = 0; k < object.getPointsLength(); k++) { - double lon = MapUtils.get31LongitudeX(object.getPoint31XTile(k)); - double lat = MapUtils.get31LatitudeY(object.getPoint31YTile(k)); - if(k > 0) { - double dd = MapUtils.getDistance(plat, plon, lat, lon); - int height = HEIGHT_UNDEFINED; - if(k == object.getPointsLength() - 1) { - height = endHeight; - } else { - int[] tps = object.getPointTypes(k); - if (tps != null) { - for (int id : tps) { - RouteTypeRule rt = object.region.quickGetEncodingRule(id); - if (rt.getTag().equals("osmand_ele_asc")) { - height = (int) (prevHeight + Float.parseFloat(rt.getValue())); - break; - } else if (rt.getTag().equals("osmand_ele_desc")) { - height = (int) (prevHeight - Float.parseFloat(rt.getValue())); - break; - } - } - } - } - pf[2*k] = (float) dd; - pf[2*k+1] = height; - if(height != HEIGHT_UNDEFINED) { - // interpolate undefined - double totalDistance = dd; - int startUndefined = k; - while(startUndefined - 1 >= 0 && pf[2*(startUndefined - 1)+1] == HEIGHT_UNDEFINED) { - startUndefined --; - totalDistance += pf[2*(startUndefined)]; - } - if(totalDistance > 0) { - double angle = (height - prevHeight) / totalDistance; - for(int j = startUndefined; j < k; j++) { - pf[2*j+1] = (float) ((pf[2*j] * angle) + pf[2*j-1]); - } - } - prevHeight = height; - } - - } else { - pf[0] = 0; - pf[1] = startHeight; - } - plat = lat; - plon = lon; - } boolean reverse = startPointIndex > endPointIndex; int st = Math.min(startPointIndex, endPointIndex); int end = Math.max(startPointIndex, endPointIndex); - float[] res = new float[(end - st + 1) * 2]; for (int k = 0; k < res.length / 2; k++) { if (k == 0) { diff --git a/OsmAnd-java/src/net/osmand/router/VehicleRouter.java b/OsmAnd-java/src/net/osmand/router/VehicleRouter.java index 3d565b039b..0971b4afc3 100644 --- a/OsmAnd-java/src/net/osmand/router/VehicleRouter.java +++ b/OsmAnd-java/src/net/osmand/router/VehicleRouter.java @@ -32,6 +32,11 @@ public interface VehicleRouter { */ public float defineObstacle(RouteDataObject road, int point); + /** + * return delay in seconds for height obstacles + */ + public double defineHeightObstacle(RouteDataObject road, short startIndex, short endIndex, float distance); + /** * return delay in seconds (0 no obstacles) */ @@ -78,5 +83,7 @@ public interface VehicleRouter { public VehicleRouter build(Map params); + + } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/search/QuickSearchCoordinatesFragment.java b/OsmAnd/src/net/osmand/plus/search/QuickSearchCoordinatesFragment.java index 383fbf3966..11decf28d0 100644 --- a/OsmAnd/src/net/osmand/plus/search/QuickSearchCoordinatesFragment.java +++ b/OsmAnd/src/net/osmand/plus/search/QuickSearchCoordinatesFragment.java @@ -437,7 +437,9 @@ public class QuickSearchCoordinatesFragment extends DialogFragment implements Os dialogFragment.getAccessibilityAssistant().lockEvents(); updateCompassVisibility(coordsView, latLon, heading); dialogFragment.getAccessibilityAssistant().unlockEvents(); - dialogFragment.getNavigationInfo().updateTargetDirection(currentLatLon, heading.floatValue()); + if(heading != null) { + dialogFragment.getNavigationInfo().updateTargetDirection(currentLatLon, heading.floatValue()); + } } }