diff --git a/DataExtractionOSM/src/net/osmand/data/MapTileDownloader.java b/DataExtractionOSM/src/net/osmand/data/MapTileDownloader.java index ff91717baf..e07a771d6e 100644 --- a/DataExtractionOSM/src/net/osmand/data/MapTileDownloader.java +++ b/DataExtractionOSM/src/net/osmand/data/MapTileDownloader.java @@ -137,7 +137,6 @@ public class MapTileDownloader { } public void refuseAllPreviousRequests(){ - //FIXME it could cause NPE in android implementation think about different style // That's very strange because exception in impl of queue (possibly wrong impl) // threadPoolExecutor.getQueue().clear(); while(!threadPoolExecutor.getQueue().isEmpty()){ diff --git a/DataExtractionOSM/src/net/osmand/render/default.render.xml b/DataExtractionOSM/src/net/osmand/render/default.render.xml index b14e7ca60c..dbd02e3e92 100644 --- a/DataExtractionOSM/src/net/osmand/render/default.render.xml +++ b/DataExtractionOSM/src/net/osmand/render/default.render.xml @@ -856,7 +856,6 @@ - diff --git a/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java b/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java index a133a3cf3c..dcdc2fb99d 100644 --- a/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java +++ b/DataExtractionOSM/src/net/osmand/router/BinaryRoutePlanner.java @@ -164,7 +164,6 @@ public class BinaryRoutePlanner { // TODO TO-DO U-TURN - // TODO write unit tests // TODO fastest/shortest way /** * Calculate route between start.segmentEnd and end.segmentStart (using A* algorithm) @@ -858,11 +857,50 @@ public class BinaryRoutePlanner { double distance = 0; for (int j = rr.getStartPointIndex(); j != rr.getEndPointIndex(); j = next) { next = plus ? j + 1 : j - 1; + if(j == rr.getStartPointIndex()) { + attachRoadSegments(ctx, result, i, j, plus); + } + if(next != rr.getEndPointIndex()) { + attachRoadSegments(ctx, result, i, next, plus); + } + double d = measuredDist(road.getPoint31XTile(j), road.getPoint31YTile(j), road.getPoint31XTile(next), road.getPoint31YTile(next)); distance += d; distOnRoadToPass += d / speed + ctx.getRouter().defineObstacle(road, j); - attachRoadSegments(ctx, result, i, j); + + List attachedRoutes = rr.getAttachedRoutes(next); + if (next != rr.getEndPointIndex() && !rr.getObject().roundabout() && attachedRoutes != null) { + float before = rr.getBearing(next, !plus); + float after = rr.getBearing(next, plus); + boolean straight = Math.abs(MapUtils.degreesDiff(before + 180, after)) < 70; + boolean split = false; + // split if needed + for (RouteSegmentResult rs : attachedRoutes) { + double diff = MapUtils.degreesDiff(before + 180, rs.getBearingBegin()); + if (Math.abs(diff) < 50) { + split = true; + } else if (!straight && Math.abs(diff) < 100) { + split = true; + } + } + if (split) { + int endPointIndex = rr.getEndPointIndex(); + RouteSegmentResult splitted = new RouteSegmentResult(rr.getObject(), next, endPointIndex); + rr.setSegmentTime((float) distOnRoadToPass); + rr.setSegmentSpeed((float) speed); + rr.setDistance((float) distance); + rr.setEndPointIndex(next); + + result.add(i + 1, splitted); + completeTime += distOnRoadToPass; + completeDistance += distance; + // switch current segment to the splitted + rr = splitted; + distOnRoadToPass = 0; + distance = 0; + } + } } // last point turn time can be added // if(i + 1 < result.size()) { distOnRoadToPass += ctx.getRouter().calculateTurnTime(); } @@ -873,29 +911,7 @@ public class BinaryRoutePlanner { completeTime += distOnRoadToPass; completeDistance += distance; } - int toUpdate = -1; - float dist = 0; - for (int i = 0; i <= result.size(); i++) { - TurnType t = null; - if (i < result.size()) { - t = getTurnInfo(result, i, leftside); - result.get(i).setTurnType(t); - } - if (t != null || i == result.size()) { - if (toUpdate >= 0) { - String turn = result.get(toUpdate).getTurnType().toString(); - if (result.get(toUpdate).getTurnType().getLanes() != null) { - turn += Arrays.toString(result.get(toUpdate).getTurnType().getLanes()); - } - result.get(toUpdate).setDescription(turn + String.format(" and go %.2f meters", dist)); - } - toUpdate = i; - dist = 0; - } - if (i < result.size()) { - dist += result.get(i).getDistance(); - } - } + addTurnInfo(leftside, result); println("ROUTE : "); double startLat = MapUtils.get31LatitudeY(start.road.getPoint31YTile(start.segmentStart)); @@ -941,6 +957,44 @@ public class BinaryRoutePlanner { } + private void addTurnInfo(boolean leftside, List result) { + int prevSegment = -1; + float dist = 0; + for (int i = 0; i <= result.size(); i++) { + TurnType t = null; + if (i < result.size()) { + t = getTurnInfo(result, i, leftside); + result.get(i).setTurnType(t); + } + if (t != null || i == result.size()) { + if (prevSegment >= 0) { + String turn = result.get(prevSegment).getTurnType().toString(); + if (result.get(prevSegment).getTurnType().getLanes() != null) { + turn += Arrays.toString(result.get(prevSegment).getTurnType().getLanes()); + } + result.get(prevSegment).setDescription(turn + String.format(" and go %.2f meters", dist)); + if(result.get(prevSegment).getTurnType().isSkipToSpeak()) { + result.get(prevSegment).setDescription(result.get(prevSegment).getDescription() +" (*)"); + } + } + prevSegment = i; + dist = 0; + } + if (i < result.size()) { + dist += result.get(i).getDistance(); + } + } + } + + private boolean highwayLowEnd(String highway) { + if (highway == null || highway.endsWith("_link") || highway.endsWith("services") || highway.endsWith("service") + || highway.endsWith("unclassified") || highway.endsWith("road")) { + return true; + } + return false; + } + + private TurnType getTurnInfo(List result, int i, boolean leftSide) { if (i == 0) { return TurnType.valueOf(TurnType.C, false); @@ -1010,21 +1064,24 @@ public class BinaryRoutePlanner { int ls = prev.getObject().getLanes(); int left = 0; int right = 0; + boolean speak = highwayLowEnd(prev.getObject().getHighway()) || highwayLowEnd(rr.getObject().getHighway()); if(attachedRoutes != null){ for(RouteSegmentResult rs : attachedRoutes){ double ex = MapUtils.degreesDiff(rs.getBearingBegin(), rr.getBearingBegin()); - if(ex < 30 && ex >= 0) { + if(ex < 60 && ex >= 0) { kl = true; int lns = rs.getObject().getLanes(); if (lns > 0) { right += lns; } - } else if(ex > -30 && ex <= 0) { + speak = speak || !highwayLowEnd(rs.getObject().getHighway()); + } else if(ex > -60 && ex <= 0) { kr = true; int lns = rs.getObject().getLanes(); if (lns > 0) { left += lns; } + speak = speak || !highwayLowEnd(rs.getObject().getHighway()); } } } @@ -1037,7 +1094,7 @@ public class BinaryRoutePlanner { if (current <= 0) { current = 1; } - if(ls >= 0 && current + left + right >= ls){ + if(ls >= 0 /*&& current + left + right >= ls*/){ lanes = new int[current + left + right]; ls = current + left + right; for(int it=0; it< ls; it++) { @@ -1051,8 +1108,10 @@ public class BinaryRoutePlanner { if (kl) { t = TurnType.valueOf(TurnType.KL, leftSide); + t.setSkipToSpeak(!speak); } else if(kr){ t = TurnType.valueOf(TurnType.KR, leftSide); + t.setSkipToSpeak(!speak); } } if(t != null) { @@ -1068,7 +1127,7 @@ public class BinaryRoutePlanner { } - private void attachRoadSegments(RoutingContext ctx, List result, int routeInd, int pointInd) { + private void attachRoadSegments(RoutingContext ctx, List result, int routeInd, int pointInd, boolean plus) { RouteSegmentResult rr = result.get(routeInd); RouteDataObject road = rr.getObject(); RoutingTile tl = loadRoutes(ctx, road.getPoint31XTile(pointInd), road.getPoint31YTile(pointInd)); @@ -1076,21 +1135,20 @@ public class BinaryRoutePlanner { // attach additional roads to represent more information about the route RouteSegmentResult previousResult = null; + // by default make same as this road id long previousRoadId = road.getId(); if (pointInd == rr.getStartPointIndex() && routeInd > 0) { previousResult = result.get(routeInd - 1); previousRoadId = previousResult.getObject().getId(); - boolean prevPlus = previousResult.getStartPointIndex() < previousResult.getEndPointIndex(); - if (prevPlus) { - if (previousResult.getStartPointIndex() < previousResult.getEndPointIndex() && - previousResult.getEndPointIndex() < previousResult.getObject().getPointsLength() - 1) { - rr.attachRoute(pointInd, new RouteSegmentResult(previousResult.getObject(), - previousResult.getEndPointIndex(), previousResult.getObject().getPointsLength() - 1)); - } else if (previousResult.getStartPointIndex() > previousResult.getEndPointIndex() && - previousResult.getEndPointIndex() > 0) { - rr.attachRoute(pointInd, new RouteSegmentResult(previousResult.getObject(), - previousResult.getEndPointIndex(), 0)); + if (previousRoadId != road.getId()) { + if (previousResult.getStartPointIndex() < previousResult.getEndPointIndex() + && previousResult.getEndPointIndex() < previousResult.getObject().getPointsLength() - 1) { + rr.attachRoute(pointInd, new RouteSegmentResult(previousResult.getObject(), previousResult.getEndPointIndex(), + previousResult.getObject().getPointsLength() - 1)); + } else if (previousResult.getStartPointIndex() > previousResult.getEndPointIndex() + && previousResult.getEndPointIndex() > 0) { + rr.attachRoute(pointInd, new RouteSegmentResult(previousResult.getObject(), previousResult.getEndPointIndex(), 0)); } } } @@ -1099,6 +1157,7 @@ public class BinaryRoutePlanner { while (routeSegment != null) { if (routeSegment.road.getId() != road.getId() && routeSegment.road.getId() != previousRoadId) { RouteDataObject addRoad = routeSegment.road; + // TODO restrictions can be considered as well int oneWay = ctx.getRouter().isOneWay(addRoad); if (oneWay >= 0 && routeSegment.segmentStart < addRoad.getPointsLength() - 1) { rr.attachRoute(pointInd, new RouteSegmentResult(addRoad, routeSegment.segmentStart, addRoad.getPointsLength() - 1)); diff --git a/DataExtractionOSM/src/net/osmand/router/RouteSegmentResult.java b/DataExtractionOSM/src/net/osmand/router/RouteSegmentResult.java index fcadb77abf..04ddb13306 100644 --- a/DataExtractionOSM/src/net/osmand/router/RouteSegmentResult.java +++ b/DataExtractionOSM/src/net/osmand/router/RouteSegmentResult.java @@ -12,7 +12,7 @@ import net.osmand.osm.MapUtils; public class RouteSegmentResult { private final RouteDataObject object; private final int startPointIndex; - private final int endPointIndex; + private int endPointIndex; private final List[] attachedRoutes; private float segmentTime; private float speed; @@ -31,16 +31,16 @@ public class RouteSegmentResult { } public void attachRoute(int roadIndex, RouteSegmentResult r){ - int st = startPointIndex < endPointIndex ? startPointIndex : endPointIndex; - if(attachedRoutes[roadIndex - st] == null) { - attachedRoutes[roadIndex - st] = new ArrayList(); + int st = Math.abs(roadIndex - startPointIndex); + if(attachedRoutes[st] == null) { + attachedRoutes[st] = new ArrayList(); } - attachedRoutes[roadIndex - st].add(r); + attachedRoutes[st].add(r); } public List getAttachedRoutes(int routeInd) { - int st = startPointIndex < endPointIndex ? startPointIndex : endPointIndex; - List list = attachedRoutes[routeInd - st]; + int st = Math.abs(routeInd - startPointIndex); + List list = attachedRoutes[st]; if(list == null) { return Collections.emptyList(); } @@ -67,6 +67,10 @@ public class RouteSegmentResult { return (float) (object.directionRoute(startPointIndex, startPointIndex < endPointIndex) / Math.PI * 180); } + public float getBearing(int point, boolean plus) { + return (float) (object.directionRoute(point, plus) / Math.PI * 180); + } + public float getBearingEnd() { return (float) (MapUtils.alignAngleDifference(object.directionRoute(endPointIndex, startPointIndex > endPointIndex) - Math.PI) / Math.PI * 180); } @@ -103,6 +107,10 @@ public class RouteSegmentResult { this.speed = speed; } + public void setEndPointIndex(int endPointIndex) { + this.endPointIndex = endPointIndex; + } + public float getSegmentSpeed() { return speed; } @@ -124,5 +132,4 @@ public class RouteSegmentResult { } - } \ No newline at end of file diff --git a/DataExtractionOSM/src/net/osmand/router/TurnType.java b/DataExtractionOSM/src/net/osmand/router/TurnType.java index 806ea0b1c3..27190729da 100644 --- a/DataExtractionOSM/src/net/osmand/router/TurnType.java +++ b/DataExtractionOSM/src/net/osmand/router/TurnType.java @@ -34,6 +34,7 @@ public class TurnType { private boolean isLeftSide; // calculated CW head rotation if previous direction to NORTH private float turnAngle; + private boolean skipToSpeak; private int[] lanes; private static TurnType getExitTurn(int out, float angle, boolean leftSide) { @@ -60,7 +61,7 @@ public class TurnType { public void setTurnAngle(float turnAngle) { this.turnAngle = turnAngle; } - + private TurnType(String value) { this.value = value; } @@ -96,6 +97,13 @@ public class TurnType { return value.equals(KR); } + public boolean isSkipToSpeak() { + return skipToSpeak; + } + public void setSkipToSpeak(boolean skipToSpeak) { + this.skipToSpeak = skipToSpeak; + } + @Override public String toString() { if(isRoundAbout()){ diff --git a/OsmAnd/res/layout/animate_route.xml b/OsmAnd/res/layout/animate_route.xml new file mode 100644 index 0000000000..4a9aeb94f9 --- /dev/null +++ b/OsmAnd/res/layout/animate_route.xml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 0294d60dd2..1c8aa79e21 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -9,6 +9,7 @@ 1. All your modified/created strings are in the top of the file (to make easier find what's translated). PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy --> + Select animate route acceleration Info Control Show monitoring state on the info pane diff --git a/OsmAnd/src/net/osmand/plus/activities/LocalIndexesActivity.java b/OsmAnd/src/net/osmand/plus/activities/LocalIndexesActivity.java index 737f501d8a..7396237620 100644 --- a/OsmAnd/src/net/osmand/plus/activities/LocalIndexesActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/LocalIndexesActivity.java @@ -477,7 +477,7 @@ public class LocalIndexesActivity extends OsmandExpandableListActivity { if (!isCancelled()) { String warning = null; File file = new File(info.getPathToData()); - // FIXME should be plugin functionality and do not use remote util directly + // TODO should be plugin functionality and do not use remote util directly warning = new OpenstreetmapRemoteUtil(LocalIndexesActivity.this, null).uploadGPXFile(tagstring, description, visibility, file); total++; if (warning == null) { diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java index 274896dab3..d035b3d1a8 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivity.java @@ -563,7 +563,7 @@ public class MapActivity extends AccessibleActivity implements IMapLocationListe final LatLon point = settings.getPointToNavigate(); if (point != null) { if (routingHelper.isRouteCalculated()) { - routingHelper.getVoiceRouter().announceCurrentDirection(); + routingHelper.getVoiceRouter().announceCurrentDirection(routingHelper.getLastFixedLocation()); } else { AccessibleToast.makeText(this, getNavigationHint(point), Toast.LENGTH_LONG).show(); } diff --git a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java index 8821a16522..49eac33fcf 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java @@ -264,4 +264,4 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { return monitoring; } -} \ No newline at end of file +} diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteAnimation.java b/OsmAnd/src/net/osmand/plus/routing/RouteAnimation.java index 320ad4f889..15f44d3684 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteAnimation.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteAnimation.java @@ -15,6 +15,9 @@ import android.content.Context; import android.content.DialogInterface; import android.location.Location; import android.location.LocationManager; +import android.view.View; +import android.widget.SeekBar; +import android.widget.TextView; public class RouteAnimation { @@ -30,6 +33,12 @@ public class RouteAnimation { if (!isRouteAnimating()) { Builder builder = new AlertDialog.Builder(ma); builder.setTitle("Do you want to use existing GPX file?"); + final View view = ma.getLayoutInflater().inflate(R.layout.animate_route, null); + ((TextView)view.findViewById(R.id.MinSpeedup)).setText("1"); //$NON-NLS-1$ + ((TextView)view.findViewById(R.id.MaxSpeedup)).setText("4"); //$NON-NLS-1$ + final SeekBar speedup = (SeekBar) view.findViewById(R.id.Speedup); + speedup.setMax(3); + builder.setView(view); builder.setPositiveButton(R.string.default_buttons_yes, new DialogInterface.OnClickListener() { @Override @@ -40,7 +49,7 @@ public class RouteAnimation { public boolean processResult(GPXUtilities.GPXFile result) { GPXRouteParams prms = new RouteProvider.GPXRouteParams(result, false, ((OsmandApplication) ma.getApplication()).getSettings()); mgr.removeUpdates(ma.getGpsListener()); - startAnimationThread(routingHelper, ma, prms.points, true, 2); + startAnimationThread(routingHelper, ma, prms.points, true, speedup.getProgress() + 1); return true; } }, true, false); diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java b/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java index 890a1025ae..868f215ef6 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteCalculationResult.java @@ -6,6 +6,7 @@ import java.util.List; import net.osmand.OsmAndFormatter; import net.osmand.osm.LatLon; +import net.osmand.osm.MapUtils; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; @@ -39,20 +40,21 @@ public class RouteCalculationResult { List locations = list == null ? new ArrayList() : new ArrayList(list); List localDirections = directions == null? new ArrayList() : new ArrayList(directions); if (!locations.isEmpty()) { - // if there is no closest points to start - add it - introduceFirstPoint(locations, localDirections, null, start); checkForDuplicatePoints(locations, localDirections); - removeUnnecessaryGoAhead(localDirections); } + if(addMissingTurns) { + removeUnnecessaryGoAhead(localDirections); + OsmandSettings settings = ((OsmandApplication) ctx.getApplicationContext()).getSettings(); + addMissingTurnsToRoute(locations, localDirections, start, end, settings.getApplicationMode(), ctx, leftSide); + // if there is no closest points to start - add it + introduceFirstPointAndLastPoint(locations, localDirections, null, start, end); + } + this.locations = Collections.unmodifiableList(locations); this.segments = new ArrayList(locations.size()); this.listDistance = new int[locations.size()]; updateListDistanceTime(); - if(addMissingTurns) { - OsmandSettings settings = ((OsmandApplication) ctx.getApplicationContext()).getSettings(); - addMissingTurnsToRoute(localDirections, start, end, settings.getApplicationMode(), ctx, leftSide); - } this.directions = Collections.unmodifiableList(localDirections); updateDirectionsTime(); } @@ -63,7 +65,8 @@ public class RouteCalculationResult { this.errorMessage = null; List locations = new ArrayList(); List segments = convertVectorResult(computeDirections, locations, list, ctx); - introduceFirstPoint(locations,computeDirections, segments, start); + introduceFirstPointAndLastPoint(locations, computeDirections, segments, start, end); + this.locations = Collections.unmodifiableList(locations); this.segments = Collections.unmodifiableList(segments); this.listDistance = new int[locations.size()]; @@ -137,9 +140,10 @@ public class RouteCalculationResult { return segmentsToPopulate; } - protected void addMissingTurnsToRoute(List originalDirections, Location start, LatLon end, ApplicationMode mode, Context ctx, + protected void addMissingTurnsToRoute(List locations, + List originalDirections, Location start, LatLon end, ApplicationMode mode, Context ctx, boolean leftSide){ - if(!isCalculated()){ + if(locations.isEmpty()){ return; } // speed m/s @@ -154,7 +158,13 @@ public class RouteCalculationResult { } List computeDirections = new ArrayList(); - int[] listDistance = getListDistance(); + + int[] listDistance = new int[locations.size()]; + listDistance[locations.size() - 1] = 0; + for (int i = locations.size() - 1; i > 0; i--) { + listDistance[i - 1] = (int) locations.get(i - 1).distanceTo(locations.get(i)); + listDistance[i - 1] += listDistance[i]; + } int previousLocation = 0; int prevBearingLocation = 0; @@ -253,15 +263,6 @@ public class RouteCalculationResult { previousInfo.setDescriptionRoute(previousInfo.getDescriptionRoute() + " " + OsmAndFormatter.getFormattedDistance(previousInfo.distance, ctx)); //$NON-NLS-1$ - // add last direction go straight (to show arrow in screen after all turns) - if(previousInfo.distance > 80){ - RouteDirectionInfo info = new RouteDirectionInfo(speed, TurnType.valueOf(TurnType.C, leftSide)); - info.distance = 0; - info.routePointOffset = locations.size() - 1; - computeDirections.add(info); - } - - if (originalDirections.isEmpty()) { originalDirections.addAll(computeDirections); } else { @@ -396,8 +397,10 @@ public class RouteCalculationResult { /** * PREPARATION * If beginning is too far from start point, then introduce GO Ahead + * @param end */ - private void introduceFirstPoint(List locations, List directions, List segs, Location start) { + private void introduceFirstPointAndLastPoint(List locations, List directions, List segs, Location start, + LatLon end) { if (!locations.isEmpty() && locations.get(0).distanceTo(start) > 200) { // add start point locations.add(0, start); @@ -415,6 +418,25 @@ public class RouteCalculationResult { directions.add(0, info); } } + RouteDirectionInfo lastDirInf = directions.size() > 0 ? directions.get(directions.size() - 1) : null; + if((lastDirInf == null || lastDirInf.routePointOffset < locations.size() - 1) && locations.size() - 1 > 0) { + String type = TurnType.C; + Location prevLast = locations.get(locations.size() - 2); + float lastBearing = prevLast.bearingTo(locations.get(locations.size() - 1)); + float[] compute = new float[2]; + Location.distanceBetween(prevLast.getLatitude(), prevLast.getLongitude(), + end.getLatitude(), end.getLongitude(), compute); + float bearingToEnd = compute[1]; + double diff = MapUtils.degreesDiff(lastBearing, bearingToEnd); + if(Math.abs(diff) > 10) { + type = diff > 0 ? TurnType.KL : TurnType.KR; + } + RouteDirectionInfo info = new RouteDirectionInfo(1, TurnType.valueOf(type, false)); + info.distance = 0; + info.afterLeftTime = 0; + info.routePointOffset = locations.size() - 1; + directions.add(info); + } } /** @@ -481,11 +503,14 @@ public class RouteCalculationResult { return 0; } - - public int[] getListDistance() { - return listDistance; + + public int getWholeDistance() { + if(listDistance.length > 0) { + return listDistance[0]; + } + return 0; } - + public boolean isCalculated() { return !locations.isEmpty(); } @@ -509,26 +534,66 @@ public class RouteCalculationResult { return null; } - public RouteDirectionInfo getNextRouteDirectionInfo(){ - if(currentDirectionInfo < directions.size() - 1){ - return directions.get(currentDirectionInfo + 1); + + /*public */NextDirectionInfo getNextRouteDirectionInfo(NextDirectionInfo info, Location fromLoc, boolean toSpeak) { + int dirInfo = currentDirectionInfo; + if (dirInfo < directions.size()) { + int dist = listDistance[currentRoute]; + int nextInd = dirInfo + 1; + if (toSpeak) { + while (nextInd < directions.size()) { + RouteDirectionInfo i = directions.get(nextInd); + if (i.getTurnType() != null && !i.getTurnType().isSkipToSpeak()) { + break; + } + nextInd++; + } + } + if (fromLoc != null) { + dist += fromLoc.distanceTo(locations.get(currentRoute)); + } + if (nextInd < directions.size()) { + info.directionInfo = directions.get(nextInd); + dist -= listDistance[directions.get(nextInd).routePointOffset]; + } + info.directionInfoInd = nextInd; + info.distanceTo = dist; + return info; } + info.directionInfoInd = -1; + info.distanceTo = -1; + info.directionInfo = null; return null; } - public RouteDirectionInfo getCurrentRouteDirectionInfo(){ - if(currentDirectionInfo < directions.size()){ - return directions.get(currentDirectionInfo); + /*public */NextDirectionInfo getNextRouteDirectionInfoAfter(NextDirectionInfo prev, NextDirectionInfo next, boolean toSpeak) { + int dirInfo = prev.directionInfoInd; + if (dirInfo < directions.size() && prev.directionInfo != null) { + int dist = listDistance[prev.directionInfo.routePointOffset]; + int nextInd = dirInfo + 1; + if (toSpeak) { + while (nextInd < directions.size()) { + RouteDirectionInfo i = directions.get(nextInd); + if (i.getTurnType() != null && !i.getTurnType().isSkipToSpeak()) { + break; + } + nextInd++; + } + } + if (nextInd < directions.size()) { + next.directionInfo = directions.get(nextInd); + dist -= listDistance[directions.get(nextInd).routePointOffset]; + } + next.distanceTo = dist; + next.directionInfoInd = nextInd; + return next; } + next.directionInfoInd = -1; + next.distanceTo = -1; + next.directionInfo = null; return null; } - public RouteDirectionInfo getNextNextRouteDirectionInfo(){ - if(currentDirectionInfo < directions.size() - 2){ - return directions.get(currentDirectionInfo + 2); - } - return null; - } - + public List getRouteDirections() { if(currentDirectionInfo < directions.size()){ if(currentDirectionInfo == 0){ @@ -559,32 +624,6 @@ public class RouteCalculationResult { return currentDirectionInfo < directions.size(); } - public int getDistanceToNextTurn(Location fromLoc) { - if (currentDirectionInfo < directions.size()) { - int dist = listDistance[currentRoute]; - if (currentDirectionInfo < directions.size() - 1) { - dist -= listDistance[directions.get(currentDirectionInfo + 1).routePointOffset]; - } - if (fromLoc != null) { - dist += fromLoc.distanceTo(locations.get(currentRoute)); - } - return dist; - } - return -1; - } - - public int getDistanceFromNextToNextNextTurn() { - if (currentDirectionInfo < directions.size() - 1) { - int dist = listDistance[directions.get(currentDirectionInfo + 1).routePointOffset]; - if (currentDirectionInfo < directions.size() - 2) { - dist -= listDistance[directions.get(currentDirectionInfo + 2).routePointOffset]; - } - return dist; - } - return -1; - } - - public int getDistanceToFinish(Location fromLoc) { if(listDistance != null && currentRoute < listDistance.length){ int dist = listDistance[currentRoute]; @@ -596,6 +635,33 @@ public class RouteCalculationResult { } return 0; } + + public int getLeftTime(Location fromLoc){ + int time = 0; + if(currentDirectionInfo < directions.size()) { + RouteDirectionInfo current = directions.get(currentDirectionInfo); + time = current.afterLeftTime; + + int distanceToNextTurn = listDistance[currentRoute]; + if(currentDirectionInfo + 1 < directions.size()) { + distanceToNextTurn -= listDistance[directions.get(currentDirectionInfo + 1).routePointOffset]; + } + Location l = locations.get(currentRoute); + if(fromLoc != null){ + distanceToNextTurn += fromLoc.distanceTo(l); + } + time += distanceToNextTurn / current.getAverageSpeed(); + } + return time; + } + public static class NextDirectionInfo { + public RouteDirectionInfo directionInfo; + public int distanceTo; + // + public int imminent; + private int directionInfoInd; + } + } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteDirectionInfo.java b/OsmAnd/src/net/osmand/plus/routing/RouteDirectionInfo.java index b8ae9f0856..c1ff4abd8e 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteDirectionInfo.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteDirectionInfo.java @@ -15,7 +15,7 @@ public class RouteDirectionInfo { private String ref; private String streetName; - + // Constructor to verify average speed always > 0 public RouteDirectionInfo(float averageSpeed, TurnType turnType) { @@ -64,7 +64,7 @@ public class RouteDirectionInfo { public TurnType getTurnType() { return turnType; } - + // calculated vars // after action (excluding expectedTime) diff --git a/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java b/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java index 5e93735875..e00702fb4c 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java +++ b/OsmAnd/src/net/osmand/plus/routing/RoutingHelper.java @@ -13,6 +13,7 @@ import net.osmand.osm.MapUtils; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.activities.ApplicationMode; +import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo; import net.osmand.plus.routing.RouteProvider.GPXRouteParams; import net.osmand.plus.routing.RouteProvider.RouteService; import net.osmand.plus.voice.CommandPlayer; @@ -153,14 +154,10 @@ public class RoutingHelper { return voiceRouter; } - - public Location getCurrentLocation() { return lastFixedLocation; } - - public void addListener(IRouteInformationListener l){ listeners.add(l); } @@ -443,6 +440,10 @@ public class RoutingHelper { return route.getDistanceToFinish(lastFixedLocation); } + public synchronized int getLeftTime() { + return route.getLeftTime(lastFixedLocation); + } + public String getGeneralRouteInformation(){ int dist = getLeftDistance(); int hours = getLeftTime() / (60 * 60); @@ -455,72 +456,27 @@ public class RoutingHelper { return route.getLocationFromRouteDirection(i); } - public RouteDirectionInfo getNextRouteDirectionInfo(){ - return route.getNextRouteDirectionInfo(); + public synchronized NextDirectionInfo getNextRouteDirectionInfo(NextDirectionInfo info, boolean toSpeak){ + NextDirectionInfo i = route.getNextRouteDirectionInfo(info, lastFixedLocation, toSpeak); + if(i != null) { + i.imminent = voiceRouter.calculateImminent(i.distanceTo, lastFixedLocation); + } + return i; } - public RouteDirectionInfo getNextNextRouteDirectionInfo(){ - return route.getNextNextRouteDirectionInfo(); + + public synchronized NextDirectionInfo getNextRouteDirectionInfoAfter(NextDirectionInfo previous, NextDirectionInfo to, boolean toSpeak){ + NextDirectionInfo i = route.getNextRouteDirectionInfoAfter(previous, to, toSpeak); + if(i != null) { + i.imminent = voiceRouter.calculateImminent(i.distanceTo, null); + } + return i; } public List getRouteDirections(){ return route.getRouteDirections(); } - public synchronized int getDistanceToNextRouteDirection() { - return route.getDistanceToNextTurn(lastFixedLocation); - } - public synchronized int getNextTurnImminent() { - if (route.directionsAvailable()) { - int dist = getDistanceToNextRouteDirection(); - // Show turnImminent for at least 5 sec (changed to 6 for device delay) if moving, cut off at 300m to avoid speed artifacts - if (lastFixedLocation != null && lastFixedLocation.hasSpeed()) { - if ((dist < (lastFixedLocation.getSpeed() * 6f)) && (dist < 300)) { - return 1; - } - } - if (dist <= 140) { - return 1; - } else if (dist <= 3500) { - //Was 3000m, but aligned again with PREPARE_LONG prompt after that was changed - return 0; - } else { - return -1; - } - } - return 0; - } - - public synchronized int getNextNextTurnImminent() { - int dist = getDistanceToNextNextRouteDirection(); - if (dist == 0) { - return -1; - } else if (dist <= 140) { - return 1; - } else if (dist <= 3000) { - return 0; - } else { - return -1; - } - } - - public synchronized int getDistanceToNextNextRouteDirection() { - return route.getDistanceFromNextToNextNextTurn(); - } - - public synchronized int getLeftTime() { - RouteDirectionInfo next = getNextRouteDirectionInfo(); - int time = 0; - if (next != null) { - time += next.afterLeftTime; - } - RouteDirectionInfo current = route.getCurrentRouteDirectionInfo(); - int distanceToNextTurn = route.getDistanceToNextTurn(lastFixedLocation); - if (current != null) { - time += distanceToNextTurn / current.getAverageSpeed(); - } - return time; - } private void recalculateRouteInBackground(final Location start, final LatLon end, final GPXRouteParams gpxRoute){ if (start == null || end == null) { @@ -552,10 +508,8 @@ public class RoutingHelper { } if (res.isCalculated()) { - int[] dist = res.getListDistance(); - int l = dist != null && dist.length > 0 ? dist[0] : 0; showMessage(context.getString(R.string.new_route_calculated_dist) - + ": " + OsmAndFormatter.getFormattedDistance(l, context)); //$NON-NLS-1$ + + ": " + OsmAndFormatter.getFormattedDistance(res.getWholeDistance(), context)); //$NON-NLS-1$ } else if (service != RouteService.OSMAND && !settings.isInternetConnectionAvailable()) { showMessage(context.getString(R.string.error_calculating_route) + ":\n" + context.getString(R.string.internet_connection_required_for_online_route), Toast.LENGTH_LONG); //$NON-NLS-1$ diff --git a/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java b/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java index 9cc61cfc85..c5e17af575 100644 --- a/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java +++ b/OsmAnd/src/net/osmand/plus/routing/VoiceRouter.java @@ -1,6 +1,7 @@ package net.osmand.plus.routing; import net.osmand.plus.activities.ApplicationMode; +import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo; import net.osmand.plus.voice.AbstractPrologCommandPlayer; import net.osmand.plus.voice.CommandBuilder; import net.osmand.plus.voice.CommandPlayer; @@ -22,7 +23,6 @@ public class VoiceRouter { private boolean mute = false; private CommandPlayer player; - private int currentDirection = 0; private int currentStatus = STATUS_UNKNOWN; private float playGoAheadDist = 0; @@ -43,6 +43,7 @@ public class VoiceRouter { protected int TURN_DISTANCE = 0; protected VoiceCommandPending pendingCommand = null; + private RouteDirectionInfo nextRouteDirection; public VoiceRouter(RoutingHelper router, CommandPlayer player) { @@ -87,8 +88,8 @@ public class VoiceRouter { public void updateAppMode(){ // turn prompt starts either at distance, or if actual-lead-time(currentSpeed) < maximum-lead-time // lead time criterion only for TURN_IN and TURN - PREPARE_LONG_DISTANCE = 3500; - PREPARE_LONG_DISTANCE_END = 3000; + PREPARE_LONG_DISTANCE = 3500; // (105 sec) - 120 km/h + PREPARE_LONG_DISTANCE_END = 3000; // (90 sec) - 120 km/h if(router.getAppMode() == ApplicationMode.PEDESTRIAN){ // prepare distance is not needed for pedestrian PREPARE_DISTANCE = 200; //(100 sec) @@ -114,7 +115,7 @@ public class VoiceRouter { DEFAULT_SPEED = 13; // 48 km/h } } - + private boolean isDistanceLess(float currentSpeed, double dist, double etalon){ if(dist < etalon || ((dist / currentSpeed) < (etalon / DEFAULT_SPEED))){ return true; @@ -129,6 +130,22 @@ public class VoiceRouter { return false; } + public int calculateImminent(float dist, Location loc){ + float speed = DEFAULT_SPEED; + if(loc != null && loc.hasSpeed()) { + speed = loc.getSpeed(); + } + if (isDistanceLess(speed, dist, TURN_IN_DISTANCE_END)) { + return 0; + } else if (isDistanceLess(speed, dist, PREPARE_DISTANCE_END)) { + return 1; + } else if (isDistanceLess(speed, dist, PREPARE_LONG_DISTANCE_END)) { + return 2; + } else { + return -1; + } + } + private void nextStatusAfter(int previousStatus){ //STATUS_UNKNOWN=0 -> STATUS_LONG_PREPARE=1 -> STATUS_PREPARE=2 -> STATUS_TURN_IN=3 -> STATUS_TURN=4 -> STATUS_TOLD=5 @@ -147,21 +164,21 @@ public class VoiceRouter { * Updates status of voice guidance * @param currentLocation */ - protected void updateStatus(Location currentLocation, boolean makeUturnWhenPossible){ - // Directly after turn: goAhead (dist), unless: - // < PREPARE_LONG_DISTANCE (3000m): playPrepareTurn - // < PREPARE_DISTANCE (1500m): playPrepareTurn - // < TURN_IN_DISTANCE (300m or 25sec): playMakeTurnIn - // < TURN_DISTANCE (60m or 5sec): playMakeTurn + protected void updateStatus(Location currentLocation, boolean makeUturnWhenPossible) { + // Directly after turn: goAhead (dist), unless: + // < PREPARE_LONG_DISTANCE (3000m): playPrepareTurn + // < PREPARE_DISTANCE (1500m): playPrepareTurn + // < TURN_IN_DISTANCE (300m or 25sec): playMakeTurnIn + // < TURN_DISTANCE (60m or 5sec): playMakeTurn float speed = DEFAULT_SPEED; - if(currentLocation != null && currentLocation.hasSpeed()){ + if (currentLocation != null && currentLocation.hasSpeed()) { speed = Math.max(currentLocation.getSpeed(), speed); } // Mechanism via STATUS_UTWP_TOLD: Until turn in the right direction, or route is re-calculated in forward direction if (makeUturnWhenPossible == true) { if (currentStatus != STATUS_UTWP_TOLD) { - if(playMakeUTwp()){ + if (playMakeUTwp()) { currentStatus = STATUS_UTWP_TOLD; playGoAheadDist = 0; } @@ -169,21 +186,12 @@ public class VoiceRouter { return; } - RouteDirectionInfo next = router.getNextRouteDirectionInfo(); - int dist = router.getDistanceToNextRouteDirection(); - - // if routing is changed update status to unknown - if(currentDirection != router.getRoute().currentDirectionInfo){ - currentDirection = router.getRoute().currentDirectionInfo; - currentStatus = STATUS_UNKNOWN; - playGoAheadDist = 0; - } - - + NextDirectionInfo nextInfo = router.getNextRouteDirectionInfo(new NextDirectionInfo(), true); // after last turn say: - if(next == null || next.distance == 0) { - // if(currentStatus <= STATUS_UNKNOWN && currentDirection > 0){ This caused this prompt to be suppressed when coming back from a UTwp situation - if(currentStatus <= STATUS_UNKNOWN){ + if (nextInfo == null || nextInfo.directionInfo.distance == 0) { + // if(currentStatus <= STATUS_UNKNOWN && currentDirection > 0){ This caused this prompt to be suppressed when coming back from a + // UTwp situation + if (currentStatus <= STATUS_UNKNOWN) { if (playGoAheadToDestination()) { currentStatus = STATUS_TOLD; playGoAheadDist = 0; @@ -191,7 +199,17 @@ public class VoiceRouter { } return; } - if(dist == 0 || currentStatus == STATUS_TOLD){ + int dist = nextInfo.distanceTo; + RouteDirectionInfo next = nextInfo.directionInfo; + + // if routing is changed update status to unknown + if (next != nextRouteDirection) { + nextRouteDirection = next; + currentStatus = STATUS_UNKNOWN; + playGoAheadDist = 0; + } + + if (dist == 0 || currentStatus == STATUS_TOLD) { // nothing said possibly that's wrong case we should say before that // however it should be checked manually ? return; @@ -213,51 +231,60 @@ public class VoiceRouter { nextStatusAfter(STATUS_PREPARE); } } - - - RouteDirectionInfo nextNext = router.getNextNextRouteDirectionInfo(); - if(statusNotPassed(STATUS_TURN) && isDistanceLess(speed, dist, TURN_DISTANCE, TURN_DEFAULT_SPEED)){ - if(next.distance < TURN_IN_DISTANCE_END) { - playMakeTurn(next, nextNext); + + NextDirectionInfo nextNextInfo = router.getNextRouteDirectionInfoAfter(nextInfo, new NextDirectionInfo(), false); + if (statusNotPassed(STATUS_TURN) && isDistanceLess(speed, dist, TURN_DISTANCE, TURN_DEFAULT_SPEED)) { + if (next.distance < TURN_IN_DISTANCE_END && nextNextInfo != null) { + playMakeTurn(next, nextNextInfo.directionInfo); } else { playMakeTurn(next, null); } nextStatusAfter(STATUS_TURN); - } else if (statusNotPassed(STATUS_TURN_IN) && isDistanceLess(speed, dist, TURN_IN_DISTANCE)){ + } else if (statusNotPassed(STATUS_TURN_IN) && isDistanceLess(speed, dist, TURN_IN_DISTANCE)) { if (dist >= TURN_IN_DISTANCE_END) { - if(isDistanceLess(speed, next.distance, TURN_DISTANCE) || next.distance < TURN_IN_DISTANCE_END) { - playMakeTurnIn(next, dist, nextNext); + if ((isDistanceLess(speed, next.distance, TURN_DISTANCE) || next.distance < TURN_IN_DISTANCE_END) && + nextNextInfo != null) { + playMakeTurnIn(next, dist, nextNextInfo.directionInfo); } else { playMakeTurnIn(next, dist, null); } } nextStatusAfter(STATUS_TURN_IN); - //} else if (statusNotPassed(STATUS_PREPARE) && isDistanceLess(speed, dist, PREPARE_DISTANCE)) { + // } else if (statusNotPassed(STATUS_PREPARE) && isDistanceLess(speed, dist, PREPARE_DISTANCE)) { } else if (statusNotPassed(STATUS_PREPARE) && (dist <= PREPARE_DISTANCE)) { if (dist >= PREPARE_DISTANCE_END) { - playPrepareTurn(next, dist); + if(next.getTurnType().keepLeft() || next.getTurnType().keepRight()){ + // do not play prepare for keep left/right + } else { + playPrepareTurn(next, dist); + } } nextStatusAfter(STATUS_PREPARE); - //} else if (statusNotPassed(STATUS_LONG_PREPARE) && isDistanceLess(speed, dist, PREPARE_LONG_DISTANCE)){ - } else if (statusNotPassed(STATUS_LONG_PREPARE) && (dist <= PREPARE_LONG_DISTANCE)){ + // } else if (statusNotPassed(STATUS_LONG_PREPARE) && isDistanceLess(speed, dist, PREPARE_LONG_DISTANCE)){ + } else if (statusNotPassed(STATUS_LONG_PREPARE) && (dist <= PREPARE_LONG_DISTANCE)) { if (dist >= PREPARE_LONG_DISTANCE_END) { playPrepareTurn(next, dist); - } + } nextStatusAfter(STATUS_LONG_PREPARE); - } else if (statusNotPassed(STATUS_UNKNOWN)){ + } else if (statusNotPassed(STATUS_UNKNOWN)) { // strange how we get here but nextStatusAfter(STATUS_UNKNOWN); - } else if(statusNotPassed(STATUS_TURN_IN) && dist < playGoAheadDist) { + } else if (statusNotPassed(STATUS_TURN_IN) && dist < playGoAheadDist) { playGoAheadDist = 0; playGoAhead(dist); } } - public void announceCurrentDirection() { - Location currentLocation = router.getCurrentLocation(); - RouteDirectionInfo next = router.getNextRouteDirectionInfo(); - int dist = router.getDistanceToNextRouteDirection(); + public void announceCurrentDirection(Location currentLocation) { + NextDirectionInfo nextInfo = router.getNextRouteDirectionInfo(new NextDirectionInfo(), true); + if(nextInfo == null) { + playGoAheadToDestination(); + return; + } + NextDirectionInfo nextNextInfo = router.getNextRouteDirectionInfoAfter(nextInfo, new NextDirectionInfo(), false); float speed = DEFAULT_SPEED; + RouteDirectionInfo next = nextInfo.directionInfo; + int dist = nextInfo.distanceTo; if(currentLocation != null && currentLocation.hasSpeed()){ speed = Math.max(currentLocation.getSpeed(), speed); @@ -268,27 +295,28 @@ public class VoiceRouter { playMakeUTwp(); break; case STATUS_UNKNOWN: - if ((currentDirection > 0) && ((next == null) || (next.distance == 0))) { + if (nextRouteDirection != null && ((next == null) || (next.distance == 0))) { playGoAheadToDestination(); } else { playGoAhead(dist); } break; case STATUS_TOLD: - if (currentDirection > 0) { + if (nextRouteDirection != null) { playGoAheadToDestination(); } break; case STATUS_TURN: - if(next.distance < TURN_IN_DISTANCE_END) { - playMakeTurn(next, router.getNextNextRouteDirectionInfo()); + if(next.distance < TURN_IN_DISTANCE_END && nextNextInfo != null) { + playMakeTurn(next, nextNextInfo.directionInfo); } else { playMakeTurn(next, null); } break; case STATUS_TURN_IN: - if(isDistanceLess(speed, next.distance, TURN_DISTANCE) || next.distance < TURN_IN_DISTANCE_END) { - playMakeTurnIn(next, dist, router.getNextNextRouteDirectionInfo()); + if((isDistanceLess(speed, next.distance, TURN_DISTANCE) || next.distance < TURN_IN_DISTANCE_END) && + nextNextInfo != null) { + playMakeTurnIn(next, dist, nextNextInfo.directionInfo); } else { playMakeTurnIn(next, dist, null); } @@ -338,8 +366,6 @@ public class VoiceRouter { play.prepareTurn(tParam, dist).play(); } else if(next.getTurnType().isRoundAbout()){ play.prepareRoundAbout(dist).play(); - } else if(next.getTurnType().keepLeft() || next.getTurnType().keepRight()){ - // do not play prepare for keep left/right } else if(next.getTurnType().getValue().equals(TurnType.TU) || next.getTurnType().getValue().equals(TurnType.TRU)){ play.prepareMakeUT(dist).play(); } @@ -389,8 +415,6 @@ public class VoiceRouter { boolean isplay = true; if(tParam != null){ play.turn(tParam); - } else if(next.getTurnType().keepLeft() || next.getTurnType().keepRight()){ - isplay = false; } else if(next.getTurnType().isRoundAbout()){ play.roundAbout(next.getTurnType().getTurnAngle(), next.getTurnType().getExitOut()); } else if(next.getTurnType().getValue().equals(TurnType.TU) || next.getTurnType().getValue().equals(TurnType.TRU)){ @@ -470,7 +494,7 @@ public class VoiceRouter { : VoiceCommandPending.ROUTE_CALCULATED, this); currentStatus = STATUS_UNKNOWN; } - currentDirection = router.getRoute().currentDirectionInfo; + nextRouteDirection = null; } public void arrivedDestinationPoint() { diff --git a/OsmAnd/src/net/osmand/plus/views/MapInfoLayer.java b/OsmAnd/src/net/osmand/plus/views/MapInfoLayer.java index 93bebabe97..4268b05d10 100644 --- a/OsmAnd/src/net/osmand/plus/views/MapInfoLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/MapInfoLayer.java @@ -10,6 +10,7 @@ import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.routing.RouteDirectionInfo; import net.osmand.plus.routing.RoutingHelper; +import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo; import net.osmand.router.TurnType; import android.content.Context; import android.graphics.Canvas; @@ -52,7 +53,6 @@ public class MapInfoLayer extends OsmandMapLayer { private float cachedRotate = 0; private boolean showArrivalTime = true; private boolean showAltitude = false; - private boolean showMiniMap = false; // layout pseudo-constants private int STATUS_BAR_MARGIN_X = 4; @@ -104,7 +104,7 @@ public class MapInfoLayer extends OsmandMapLayer { paintSmallText = new Paint(); paintSmallText.setStyle(Style.FILL_AND_STROKE); paintSmallText.setColor(Color.BLACK); - paintSmallText.setTextSize(18 * scaleCoefficient); + paintSmallText.setTextSize(19 * scaleCoefficient); paintSmallText.setAntiAlias(true); paintSmallText.setStrokeWidth(4); @@ -233,10 +233,10 @@ public class MapInfoLayer extends OsmandMapLayer { paintSmallSubText.setColor(color); } if(paintText.isFakeBoldText() != bold) { - paintText.setFakeBoldText(true); - paintSubText.setFakeBoldText(true); - paintSmallText.setFakeBoldText(true); - paintSmallSubText.setFakeBoldText(true); + paintText.setFakeBoldText(bold); + paintSubText.setFakeBoldText(bold); + paintSmallText.setFakeBoldText(bold); + paintSmallSubText.setFakeBoldText(bold); } // update data on draw rightStack.updateInfo(); @@ -464,17 +464,11 @@ public class MapInfoLayer extends OsmandMapLayer { return distanceControl; } - private MiniMapControl createMiniMapControl() { + protected MiniMapControl createMiniMapControl() { final MiniMapControl miniMapControl = new MiniMapControl(map, view) { @Override public boolean updateInfo() { boolean visible = false; - if (routeLayer != null && routeLayer.getHelper().isRouterEnabled() && routeLayer.getHelper().isFollowingMode()) { - if (showMiniMap && !routeLayer.getPath().isEmpty()) { - visible = true; - miniMapPath = routeLayer.getPath(); - } - } updateVisibility(visible); return super.updateInfo(); } @@ -483,7 +477,7 @@ public class MapInfoLayer extends OsmandMapLayer { miniMapControl.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - showMiniMap = false; +// showMiniMap = false; miniMapControl.invalidate(); view.refreshMap(); } @@ -494,36 +488,43 @@ public class MapInfoLayer extends OsmandMapLayer { private NextTurnInfoControl createNextNextInfoControl() { final RoutingHelper routingHelper = routeLayer.getHelper(); final NextTurnInfoControl nextTurnInfo = new NextTurnInfoControl(map, paintSmallText, paintSmallSubText, true) { + NextDirectionInfo calc1 = new NextDirectionInfo(); @Override public boolean updateInfo() { boolean visible = false; if (routeLayer != null && routingHelper.isRouterEnabled() && routingHelper.isFollowingMode()) { boolean uturnWhenPossible = routingHelper.makeUturnWhenPossible(); - int d; - if(uturnWhenPossible) { - d = routingHelper.getDistanceToNextRouteDirection() ; - } else { - d = routingHelper.getDistanceToNextNextRouteDirection(); + NextDirectionInfo r = routingHelper.getNextRouteDirectionInfo(calc1, false); + if (!uturnWhenPossible) { + if (r != null) { + // next turn is very close (show next next with false to speak) + if (r.imminent >= 0 && r.imminent < 2) { + r = routingHelper.getNextRouteDirectionInfoAfter(r, calc1, false); + } else { + r = routingHelper.getNextRouteDirectionInfo(calc1, true); + if (r != null) { + r = routingHelper.getNextRouteDirectionInfoAfter(r, calc1, true); + } + } + } } - if (d >= 0 && !showMiniMap) { + if (r != null && r.distanceTo > 0) { visible = true; - RouteDirectionInfo next = uturnWhenPossible? routingHelper.getNextRouteDirectionInfo() : - routingHelper.getNextNextRouteDirectionInfo(); - if (next == null) { + if (r == null || r.directionInfo == null) { if (turnType != null) { turnType = null; invalidate(); } - } else if (!Algoritms.objectEquals(turnType, next.getTurnType())) { - turnType = next.getTurnType(); + } else if (!Algoritms.objectEquals(turnType, r.directionInfo.getTurnType())) { + turnType = r.directionInfo.getTurnType(); TurnPathHelper.calcTurnPath(pathForTurn, turnType, pathTransform); invalidate(); } - if (distChanged(d, nextTurnDirection)) { + if (distChanged(r.distanceTo, nextTurnDirection)) { invalidate(); - nextTurnDirection = d; + nextTurnDirection = r.distanceTo; } - int imminent = uturnWhenPossible? routingHelper.getNextTurnImminent() : routingHelper.getNextNextTurnImminent(); + int imminent = r.imminent; if (turnImminent != imminent) { turnImminent = imminent; invalidate(); @@ -555,7 +556,6 @@ public class MapInfoLayer extends OsmandMapLayer { // nextTurnInfo.turnImminent = (nextTurnInfo.turnImminent + 1) % 3; // nextTurnInfo.nextTurnDirection = 580; // TurnPathHelper.calcTurnPath(nextTurnInfo.pathForTurn, nexsweepAngletTurnInfo.turnType,nextTurnInfo.pathTransform); - // showMiniMap = true; view.refreshMap(); } @@ -565,47 +565,17 @@ public class MapInfoLayer extends OsmandMapLayer { return nextTurnInfo; } - private NextTurnInfoControl createAlarmInfoControl() { + // FIXME alarm control + protected NextTurnInfoControl createAlarmInfoControl() { final RoutingHelper routingHelper = routeLayer.getHelper(); final NextTurnInfoControl nextTurnInfo = new NextTurnInfoControl(map, paintSmallText, paintSmallSubText, true) { @Override public boolean updateInfo() { boolean visible = false; if (routeLayer != null && routingHelper.isRouterEnabled() && routingHelper.isFollowingMode()) { - boolean uturnWhenPossible = routingHelper.makeUturnWhenPossible(); - int d; - if(uturnWhenPossible) { - d = routingHelper.getDistanceToNextRouteDirection() ; - } else { - d = routingHelper.getDistanceToNextNextRouteDirection(); - } - if (d >= 0 && !showMiniMap) { - visible = true; - RouteDirectionInfo next = uturnWhenPossible? routingHelper.getNextRouteDirectionInfo() : - routingHelper.getNextNextRouteDirectionInfo(); - if (next == null) { - if (turnType != null) { - turnType = null; - invalidate(); - } - } else if (!Algoritms.objectEquals(turnType, next.getTurnType())) { - turnType = next.getTurnType(); - TurnPathHelper.calcTurnPath(pathForTurn, turnType, pathTransform); - invalidate(); - } - if (distChanged(d, nextTurnDirection)) { - invalidate(); - nextTurnDirection = d; - } - int imminent = uturnWhenPossible? routingHelper.getNextTurnImminent() : routingHelper.getNextNextTurnImminent(); - if (turnImminent != imminent) { - turnImminent = imminent; - invalidate(); - } - } +// boolean uturnWhenPossible = routingHelper.makeUturnWhenPossible(); } updateVisibility(visible); - return true; } }; @@ -617,32 +587,44 @@ public class MapInfoLayer extends OsmandMapLayer { private NextTurnInfoControl createNextInfoControl() { final RoutingHelper routingHelper = routeLayer.getHelper(); final NextTurnInfoControl nextTurnInfo = new NextTurnInfoControl(map, paintText, paintSubText, false) { + NextDirectionInfo calc1 = new NextDirectionInfo(); + TurnType straight = TurnType.valueOf(TurnType.C, true); + @Override public boolean updateInfo() { boolean visible = false; if (routeLayer != null && routingHelper.isRouterEnabled() && routingHelper.isFollowingMode()) { - int d = routeLayer.getHelper().getDistanceToNextRouteDirection(); - makeUturnWhenPossible = routingHelper.makeUturnWhenPossible(); - if (routingHelper.makeUturnWhenPossible() == true) { - if (!showMiniMap) { - visible = true; - turnImminent = 1; - turnType = TurnType.valueOf(TurnType.TU, view.getSettings().LEFT_SIDE_NAVIGATION.get()); - TurnPathHelper.calcTurnPath(pathForTurn, turnType, pathTransform); - invalidate(); - } + if (makeUturnWhenPossible) { + visible = true; + turnImminent = 1; + turnType = TurnType.valueOf(TurnType.TU, view.getSettings().LEFT_SIDE_NAVIGATION.get()); + TurnPathHelper.calcTurnPath(pathForTurn, turnType, pathTransform); + invalidate(); } else { - if (d >= 0 && !showMiniMap) { + NextDirectionInfo r = routingHelper.getNextRouteDirectionInfo(calc1, false); + boolean showStraight = false; + if (r != null) { + RouteDirectionInfo toShowWithoutSpeak = r.directionInfo; + if (r.imminent >= 0 && r.imminent < 2) { + // next turn is very close (show it) + } else { + r = routingHelper.getNextRouteDirectionInfo(calc1, true); + if(calc1.directionInfo != toShowWithoutSpeak){ + // show straight and grey because it is not the closest turn + showStraight = r.imminent == -1; + } + } + } + if (r != null && r.distanceTo > 0) { visible = true; - RouteDirectionInfo next = routeLayer.getHelper().getNextRouteDirectionInfo(); - if (next == null) { + if (r.directionInfo == null) { if (turnType != null) { turnType = null; invalidate(); } - } else if (!Algoritms.objectEquals(turnType, next.getTurnType())) { - turnType = next.getTurnType(); + } else if (!Algoritms.objectEquals(turnType, showStraight ? straight : r.directionInfo.getTurnType())) { + turnType = showStraight ? straight : r.directionInfo.getTurnType(); TurnPathHelper.calcTurnPath(pathForTurn, turnType, pathTransform); if (turnType.getExitOut() > 0) { exitOut = turnType.getExitOut() + ""; //$NON-NLS-1$ @@ -651,12 +633,12 @@ public class MapInfoLayer extends OsmandMapLayer { } invalidate(); } - if (distChanged(d, nextTurnDirection)) { + if (distChanged(r.distanceTo, nextTurnDirection)) { invalidate(); - nextTurnDirection = d; + nextTurnDirection = r.distanceTo; } - if(turnImminent != routingHelper.getNextTurnImminent()){ - turnImminent = routingHelper.getNextTurnImminent(); + if (turnImminent != r.imminent) { + turnImminent = r.imminent; invalidate(); } } @@ -687,7 +669,7 @@ public class MapInfoLayer extends OsmandMapLayer { // nextTurnInfo.turnImminent = (nextTurnInfo.turnImminent + 1) % 3; // nextTurnInfo.nextTurnDirection = 580; // TurnPathHelper.calcTurnPath(nextTurnInfo.pathForTurn, nextTurnInfo.turnType,nextTurnInfo.pathTransform); - showMiniMap = true; +// showMiniMap = true; nextTurnInfo.requestLayout(); view.refreshMap(); } @@ -776,7 +758,6 @@ public class MapInfoLayer extends OsmandMapLayer { private static final float miniCoeff = 2f; private MapInfoControl createLanesControl() { - final RoutingHelper routingHelper = routeLayer.getHelper(); final Path laneStraight = new Path(); Matrix pathTransform = new Matrix(); pathTransform.postScale(scaleCoefficient / miniCoeff, scaleCoefficient / miniCoeff); @@ -793,9 +774,12 @@ public class MapInfoLayer extends OsmandMapLayer { paintRouteDirection.setAntiAlias(true); final float w = 72 * scaleCoefficient / miniCoeff; + + final RoutingHelper routingHelper = routeLayer.getHelper(); final MapInfoControl lanesControl = new MapInfoControl(map) { int[] lanes = null; + boolean imminent = false; @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -812,7 +796,7 @@ public class MapInfoLayer extends OsmandMapLayer { // canvas.translate((int) (16 * scaleCoefficient), 0); for (int i = 0; i < lanes.length; i++) { if ((lanes[i] & 1) == 1) { - paintRouteDirection.setColor(getResources().getColor(R.color.nav_arrow)); + paintRouteDirection.setColor(imminent ? getResources().getColor(R.color.nav_arrow_imminent) : getResources().getColor(R.color.nav_arrow)); } else { paintRouteDirection.setColor(getResources().getColor(R.color.nav_arrow_distant)); } @@ -827,32 +811,41 @@ public class MapInfoLayer extends OsmandMapLayer { @Override public boolean updateInfo() { boolean visible = false; - RouteDirectionInfo next = null; - int dist = 0; + int locimminent = -1; + int[] loclanes = null; if (routeLayer != null && routingHelper.isRouteCalculated()) { if (routingHelper.isRouterEnabled() && routingHelper.isFollowingMode()) { - next = routingHelper.getNextRouteDirectionInfo(); - dist = routingHelper.getDistanceToNextRouteDirection(); + NextDirectionInfo r = routingHelper.getNextRouteDirectionInfo(new NextDirectionInfo(), false); + if(r != null && r.directionInfo != null && r.directionInfo.getTurnType() != null) { + loclanes = r.directionInfo.getTurnType().getLanes(); + locimminent = r.imminent; + // Do not show too far + if(locimminent == 2 || locimminent < 0) { + loclanes = null; + } + } } else { - dist = 0; int di = map.getMapLayers().getRouteInfoLayer().getDirectionInfo(); if (di >= 0 && map.getMapLayers().getRouteInfoLayer().isVisible()) { - next = routingHelper.getRouteDirections().get(di); + RouteDirectionInfo next = routingHelper.getRouteDirections().get(di); + if(next != null) { + loclanes = next.getTurnType().getLanes(); + } } } } - if (next == null || dist > 450 || next.getTurnType().getLanes() == null) { - if (lanes != null) { - lanes = null; + visible = loclanes != null && loclanes.length > 0; + if (visible) { + if (!Arrays.equals(lanes, loclanes)) { + lanes = loclanes; requestLayout(); invalidate(); } - } else if (lanes == null || !Arrays.equals(lanes, next.getTurnType().getLanes())) { - lanes = next.getTurnType().getLanes(); - requestLayout(); - invalidate(); + if ((locimminent == 0) != imminent) { + imminent = (locimminent == 0); + invalidate(); + } } - visible = lanes != null && lanes.length > 0; updateVisibility(visible); return true; } diff --git a/OsmAnd/src/net/osmand/plus/views/NextTurnInfoControl.java b/OsmAnd/src/net/osmand/plus/views/NextTurnInfoControl.java index b5a91d136a..8d7ca62b67 100644 --- a/OsmAnd/src/net/osmand/plus/views/NextTurnInfoControl.java +++ b/OsmAnd/src/net/osmand/plus/views/NextTurnInfoControl.java @@ -85,10 +85,10 @@ public class NextTurnInfoControl extends MapInfoControl { protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (pathForTurn != null) { - if (turnImminent == 1) { - paintRouteDirection.setColor(getResources().getColor(R.color.nav_arrow_imminent)); - } else if (turnImminent == 0) { + if (turnImminent > 0) { paintRouteDirection.setColor(getResources().getColor(R.color.nav_arrow)); + } else if (turnImminent == 0) { + paintRouteDirection.setColor(getResources().getColor(R.color.nav_arrow_imminent)); } else { paintRouteDirection.setColor(getResources().getColor(R.color.nav_arrow_distant)); } @@ -117,9 +117,9 @@ public class NextTurnInfoControl extends MapInfoControl { float mt = textPaint.measureText(text); if (!horisontalMini) { float startX = Math.max((getWWidth() - st - mt) / 2, 2 * scaleCoefficient); - drawShadowText(canvas, text, startX, getWHeight() - 5 * scaleCoefficient, textPaint); + drawShadowText(canvas, text, startX, getWHeight() - 3 * scaleCoefficient, textPaint); if (subtext != null) { - drawShadowText(canvas, subtext, startX + 2 * scaleCoefficient + mt, getWHeight() - 5 * scaleCoefficient, subtextPaint); + drawShadowText(canvas, subtext, startX + 2 * scaleCoefficient + mt, getWHeight() - 3 * scaleCoefficient, subtextPaint); } } else { drawShadowText(canvas, text, 72 * scaleCoefficient / miniCoeff + 2 * scaleCoefficient, diff --git a/OsmAnd/src/net/osmand/plus/views/TurnPathHelper.java b/OsmAnd/src/net/osmand/plus/views/TurnPathHelper.java index 31b328c1c7..78861944c5 100644 --- a/OsmAnd/src/net/osmand/plus/views/TurnPathHelper.java +++ b/OsmAnd/src/net/osmand/plus/views/TurnPathHelper.java @@ -34,7 +34,7 @@ public class TurnPathHelper { if (TurnType.C.equals(turnType.getValue())) { int h = (int) (ha - hpartArrowL - 16); - pathForTurn.rMoveTo(th / 2, 0); + pathForTurn.rMoveTo(th, 0); pathForTurn.rLineTo(0, -h); pathForTurn.rLineTo(hpartArrowL, 0); pathForTurn.rLineTo(-harrowL / 2, -harrowL / 2); // center