Update turn information and lanes information

This commit is contained in:
Victor Shcherb 2012-07-08 16:00:10 +02:00
parent aa90c347ef
commit d715f1317f
18 changed files with 485 additions and 347 deletions

View file

@ -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()){

View file

@ -856,7 +856,6 @@
<!-- Water, night color 330099 -->
<group>
<!-- FIXME delete this block -->
<filter minzoom="1" tag="natural" value="coastline" color_2="#2Aff7c00" strokeWidth_2="1"/>
<filter minzoom="4" tag="natural" value="water"/>
<filter minzoom="4" tag="natural" value="lake"/>

View file

@ -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<RouteSegmentResult> 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<RouteSegmentResult> 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<RouteSegmentResult> 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<RouteSegmentResult> result, int routeInd, int pointInd) {
private void attachRoadSegments(RoutingContext ctx, List<RouteSegmentResult> 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));

View file

@ -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<RouteSegmentResult>[] 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<RouteSegmentResult>();
int st = Math.abs(roadIndex - startPointIndex);
if(attachedRoutes[st] == null) {
attachedRoutes[st] = new ArrayList<RouteSegmentResult>();
}
attachedRoutes[roadIndex - st].add(r);
attachedRoutes[st].add(r);
}
public List<RouteSegmentResult> getAttachedRoutes(int routeInd) {
int st = startPointIndex < endPointIndex ? startPointIndex : endPointIndex;
List<RouteSegmentResult> list = attachedRoutes[routeInd - st];
int st = Math.abs(routeInd - startPointIndex);
List<RouteSegmentResult> 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 {
}
}

View file

@ -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()){

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="vertical">
<TextView android:text="@string/select_animate_speedup" android:gravity="center"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginTop="5dp"/>
<SeekBar android:id="@+id/Speedup" android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginTop="5dp"/>
<LinearLayout
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginTop="5dp">
<TextView android:text="10" android:gravity="left" android:layout_weight="0.5" android:id="@+id/MinSpeedup"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView android:text="15" android:gravity="right" android:layout_weight="0.5" android:id="@+id/MaxSpeedup"
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>

View file

@ -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
-->
<string name="select_animate_speedup">Select animate route acceleration</string>
<string name="monitoring_info_control">Info Control</string>
<string name="monitoring_info_control_desc">Show monitoring state on the info pane</string>

View file

@ -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) {

View file

@ -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();
}

View file

@ -264,4 +264,4 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
return monitoring;
}
}
}

View file

@ -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);

View file

@ -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<Location> locations = list == null ? new ArrayList<Location>() : new ArrayList<Location>(list);
List<RouteDirectionInfo> localDirections = directions == null? new ArrayList<RouteDirectionInfo>() : new ArrayList<RouteDirectionInfo>(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<RouteSegmentResult>(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<Location> locations = new ArrayList<Location>();
List<RouteSegmentResult> 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<RouteDirectionInfo> originalDirections, Location start, LatLon end, ApplicationMode mode, Context ctx,
protected void addMissingTurnsToRoute(List<Location> locations,
List<RouteDirectionInfo> 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<RouteDirectionInfo> computeDirections = new ArrayList<RouteDirectionInfo>();
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<Location> locations, List<RouteDirectionInfo> directions, List<RouteSegmentResult> segs, Location start) {
private void introduceFirstPointAndLastPoint(List<Location> locations, List<RouteDirectionInfo> directions, List<RouteSegmentResult> 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<RouteDirectionInfo> 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;
}
}

View file

@ -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)

View file

@ -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<RouteDirectionInfo> 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$

View file

@ -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() {

View file

@ -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;
}

View file

@ -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,

View file

@ -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