Add turn types to offline routing

This commit is contained in:
Victor Shcherb 2012-06-21 09:18:08 +02:00
parent fb1815c01d
commit 794c3106cf
15 changed files with 152 additions and 90 deletions

View file

@ -172,7 +172,7 @@ public class BinaryRoutePlanner {
* Calculate route between start.segmentEnd and end.segmentStart (using A* algorithm)
* return list of segments
*/
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, RouteSegment start, RouteSegment end) throws IOException {
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, RouteSegment start, RouteSegment end, boolean leftSideNavigation) throws IOException {
// measure time
ctx.timeToLoad = 0;
ctx.visitedSegments = 0;
@ -281,7 +281,7 @@ public class BinaryRoutePlanner {
printDebugMemoryInformation(ctx, graphDirectSegments, graphReverseSegments, visitedDirectSegments, visitedOppositeSegments);
// 4. Route is found : collect all segments and prepare result
return prepareResult(ctx, start, end);
return prepareResult(ctx, start, end, leftSideNavigation);
}
@ -806,7 +806,7 @@ public class BinaryRoutePlanner {
/**
* Helper method to prepare final result
*/
private List<RouteSegmentResult> prepareResult(RoutingContext ctx, RouteSegment start, RouteSegment end) {
private List<RouteSegmentResult> prepareResult(RoutingContext ctx, RouteSegment start, RouteSegment end, boolean leftside) {
List<RouteSegmentResult> result = new ArrayList<RouteSegmentResult>();
RouteSegment segment = ctx.finalReverseRoute;
@ -861,22 +861,26 @@ public class BinaryRoutePlanner {
completeTime += distOnRoadToPass;
completeDistance += distance;
}
for (int i = 0; i < result.size(); i++) {
result.get(i).setDescription(getDescription(result, i));
}
// update distance description
int toUpdate = 0;
for (int i = 1; i < result.size(); i++) {
if (result.get(i).getDescription().length() != 0) {
float dist = 0;
for (int j = toUpdate; j < i; j++) {
dist += result.get(j).getDistance();
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) {
result.get(toUpdate).setDescription(
result.get(toUpdate).getTurnType().toString() + String.format(" and go %.2f meters", dist));
}
result.get(toUpdate).setDescription(result.get(toUpdate).getDescription() + String.format(" %.2f meters", dist));
toUpdate = i;
dist = 0;
}
if ( i < result.size()) {
dist += result.get(i).getDistance();
}
}
if (PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST) {
println("ROUTE : ");
double startLat = MapUtils.get31LatitudeY(start.road.getPoint31YTile(start.segmentStart));
@ -903,20 +907,22 @@ public class BinaryRoutePlanner {
}
private String getDescription(List<RouteSegmentResult> result, int i) {
private TurnType getTurnInfo(List<RouteSegmentResult> result, int i, boolean leftSide) {
if (i == 0) {
return "Go ahead ";
return TurnType.valueOf(TurnType.C, false);
}
RouteSegmentResult prev = result.get(i - 1) ;
if(prev.getObject().roundabout()) {
return "";
return null;
}
RouteSegmentResult rr = result.get(i);
if (rr.getObject().roundabout()) {
int exit = 1;
RouteSegmentResult last = rr;
for (int j = i; j < result.size(); j++) {
RouteSegmentResult rnext = result.get(j);
if (rnext.getObject().roundabout()) {
last = rnext;
boolean plus = rnext.getStartPointIndex() < rnext.getEndPointIndex();
int k = rnext.getStartPointIndex();
if (j == i) {
@ -933,31 +939,34 @@ public class BinaryRoutePlanner {
}
}
// combine all roundabouts
return "Round (exit " + exit + ") and go ";
TurnType t = TurnType.valueOf("EXIT"+exit, leftSide);
t.setTurnAngle((float) MapUtils.degreesDiff(last.getBearingBegin(), prev.getBearingEnd()));
return t;
}
String description = "";
TurnType t = null;
if (prev != null) {
// add description about turn
double mpi = MapUtils.degreesDiff(prev.getBearingEnd(), rr.getBearingBegin());
if (mpi >= 50) {
if (mpi < 60) {
description = "Turn slightly left and go";
t = TurnType.valueOf(TurnType.TSLL, leftSide);
} else if (mpi < 120) {
description = "Turn left and go";
t = TurnType.valueOf(TurnType.TL, leftSide);
} else if (mpi < 135) {
description = "Turn sharply left and go";
t = TurnType.valueOf(TurnType.TSHL, leftSide);
} else {
description = "Make uturn and go";
t = TurnType.valueOf(TurnType.TU, leftSide);
}
} else if (mpi < -50) {
if (mpi > -60) {
description = "Turn slightly right and go";
t = TurnType.valueOf(TurnType.TSLR, leftSide);
} else if (mpi > -120) {
description = "Turn right and go";
t = TurnType.valueOf(TurnType.TR, leftSide);
} else if (mpi > -135) {
description = "Turn right left and go";
t = TurnType.valueOf(TurnType.TSHR, leftSide);
} else {
description = "Make uturn and go";
t = TurnType.valueOf(TurnType.TU, leftSide);
}
} else {
// keep left/right
@ -967,21 +976,24 @@ public class BinaryRoutePlanner {
if(attachedRoutes != null){
for(RouteSegmentResult rs : attachedRoutes){
double ex = MapUtils.degreesDiff(rs.getBearingBegin(), rr.getBearingBegin());
if(ex < 40 && ex >= 0) {
if(ex < 30 && ex >= 0) {
kl = true;
} else if(ex > -40 && ex <= 0) {
} else if(ex > -30 && ex <= 0) {
kr = true;
}
}
}
if (kl) {
description = "Keep left and go";
t = TurnType.valueOf(TurnType.KL, leftSide);
} else if(kr){
description = "Keep right and go";
t = TurnType.valueOf(TurnType.KR, leftSide);
}
}
if(t != null) {
t.setTurnAngle((float) -mpi);
}
}
return description;
return t;
}

View file

@ -18,6 +18,8 @@ public class RouteSegmentResult {
private float speed;
private float distance;
private String description = "";
// this make not possible to make turns in between segment result for now
private TurnType turnType;
@SuppressWarnings("unchecked")
public RouteSegmentResult(RouteDataObject object, int startPointIndex, int endPointIndex) {
@ -45,6 +47,13 @@ public class RouteSegmentResult {
return list;
}
public TurnType getTurnType() {
return turnType;
}
public void setTurnType(TurnType turnType) {
this.turnType = turnType;
}
public RouteDataObject getObject() {
return object;

View file

@ -1,4 +1,4 @@
package net.osmand.plus.routing;
package net.osmand.router;
public class TurnType {
public static final String C = "C"; // continue (go straight) //$NON-NLS-1$
@ -75,4 +75,34 @@ public class TurnType {
public boolean isRoundAbout() {
return value.equals("EXIT"); //$NON-NLS-1$
}
@Override
public String toString() {
if(isRoundAbout()){
return "Take " + getExitOut() + " exit";
} else if(value.equals(C)) {
return "Go ahead";
} else if(value.equals(TSLL)) {
return "Turn slightly left";
} else if(value.equals(TL)) {
return "Turn left";
} else if(value.equals(TSHL)) {
return "Turn sharply left";
} else if(value.equals(TSLR)) {
return "Turn slightly right";
} else if(value.equals(TR)) {
return "Turn right";
} else if(value.equals(TSHR)) {
return "Turn sharply right";
} else if(value.equals(TU)) {
return "Make uturn";
} else if(value.equals(TRU)) {
return "Make uturn";
} else if(value.equals(KL)) {
return "Keep left";
} else if(value.equals(KR)) {
return "Keep right";
}
return super.toString();
}
}

View file

@ -100,7 +100,7 @@ public class RouterTestsSuite {
throw new IllegalArgumentException("End segment is not found for test : " + testDescription);
}
List<RouteSegmentResult> route = planner.searchRoute(ctx, startSegment, endSegment);
List<RouteSegmentResult> route = planner.searchRoute(ctx, startSegment, endSegment, false);
NodeList segments = testCase.getElementsByTagName("segment");

View file

@ -630,7 +630,7 @@ public class MapRouterLayer implements MapPanelLayer {
});
List<RouteSegmentResult> searchRoute = router.searchRoute(ctx, st, e);
List<RouteSegmentResult> searchRoute = router.searchRoute(ctx, st, e, false);
if (animateRoutingCalculation) {
playPauseButton.setVisible(false);
nextTurn.setText("FINISH");

View file

@ -9,6 +9,9 @@
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="route_roundabout">Roundabout : take %1$d exit</string>
<string name="route_kl">Keep left</string>
<string name="route_kr">Keep right</string>
<string name="rendering_attr_noPolygons_description">Make all areal land features on map transparent</string>
<string name="rendering_attr_noPolygons_name">No polygons</string>
<string name="rendering_attr_appMode_name">Rendering mode</string>

View file

@ -14,13 +14,11 @@ import net.osmand.Algoritms;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.IProgress;
import net.osmand.access.AccessibleToast;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.ResourceManager;
import net.osmand.plus.activities.LocalIndexHelper.LocalIndexInfo;
import net.osmand.plus.activities.LocalIndexHelper.LocalIndexType;
import net.osmand.plus.development.OsmandDevelopmentPlugin;
import net.osmand.plus.osmedit.OpenstreetmapRemoteUtil;
import android.app.Activity;
import android.app.AlertDialog;
@ -46,15 +44,15 @@ import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
public class LocalIndexesActivity extends OsmandExpandableListActivity {

View file

@ -1,7 +1,7 @@
package net.osmand.plus.activities;
import android.app.Activity;
import net.osmand.plus.activities.search.SearchActivity;
import android.app.Activity;
public class OsmandIntents {

View file

@ -10,6 +10,7 @@ import net.osmand.osm.MapUtils;
import net.osmand.plus.R;
import net.osmand.plus.routing.RouteProvider.GPXRouteParams;
import net.osmand.router.RouteSegmentResult;
import net.osmand.router.TurnType;
import android.content.Context;
import android.location.Location;
@ -43,6 +44,35 @@ public class RouteCalculationResult {
}
}
public String toString(TurnType type, Context ctx) {
if(type.isRoundAbout()){
return ctx.getString(R.string.route_roundabout, type.getExitOut());
} else if(type.getValue().equals(TurnType.C)) {
return ctx.getString(R.string.route_head);
} else if(type.getValue().equals(TurnType.TSLL)) {
return ctx.getString(R.string.route_tsll);
} else if(type.getValue().equals(TurnType.TL)) {
return ctx.getString(R.string.route_tl);
} else if(type.getValue().equals(TurnType.TSHL)) {
return ctx.getString(R.string.route_tshl);
} else if(type.getValue().equals(TurnType.TSLR)) {
return ctx.getString(R.string.route_tslr);
} else if(type.getValue().equals(TurnType.TR)) {
return ctx.getString(R.string.route_tr);
} else if(type.getValue().equals(TurnType.TSHR)) {
return ctx.getString(R.string.route_tshr);
} else if(type.getValue().equals(TurnType.TU)) {
return ctx.getString(R.string.route_tu);
} else if(type.getValue().equals(TurnType.TRU)) {
return ctx.getString(R.string.route_tu);
} else if(type.getValue().equals(TurnType.KL)) {
return ctx.getString(R.string.route_kl);
} else if(type.getValue().equals(TurnType.KR)) {
return ctx.getString(R.string.route_kr);
}
return "";
}
public RouteCalculationResult(List<RouteSegmentResult> list, Location start, LatLon end,
Context ctx, boolean leftSide) {
@ -50,6 +80,8 @@ public class RouteCalculationResult {
this.errorMessage = null;
this.locations = new ArrayList<Location>();
float prevDirectionTime = 0;
float prevDirectionDistance = 0;
for (int routeInd = 0; routeInd < list.size(); routeInd++) {
RouteSegmentResult s = list.get(routeInd);
boolean plus = s.getStartPointIndex() < s.getEndPointIndex();
@ -74,55 +106,29 @@ public class RouteCalculationResult {
i--;
}
}
TurnType turn;
String description;
if (routeInd == 0) {
turn = TurnType.valueOf(TurnType.C, leftSide);
description = ctx.getString(R.string.route_head);
} else {
RouteSegmentResult prev = list.get(routeInd - 1);
double mpi = MapUtils.degreesDiff(prev.getBearingEnd(), s.getBearingBegin());
turn = TurnType.valueOf(TurnType.C, leftSide);
description = ctx.getString(R.string.route_head);
if(mpi >= 50) {
if(mpi < 60) {
turn = TurnType.valueOf(TurnType.TSLL, leftSide);
description = ctx.getString(R.string.route_tsll);
} else if(mpi < 120) {
turn = TurnType.valueOf(TurnType.TL, leftSide);
description = ctx.getString(R.string.route_tl);
} else if(mpi < 135) {
turn = TurnType.valueOf(TurnType.TSHL, leftSide);
description = ctx.getString(R.string.route_tshl);
} else {
turn = TurnType.valueOf(TurnType.TU, leftSide);
description = ctx.getString(R.string.route_tu);
}
} else if (mpi < - 50){
if(mpi > - 60) {
turn = TurnType.valueOf(TurnType.TSLR, leftSide);
description = ctx.getString(R.string.route_tslr);
} else if(mpi > - 120) {
turn = TurnType.valueOf(TurnType.TR, leftSide);
description = ctx.getString(R.string.route_tr);
} else if(mpi > - 135) {
turn = TurnType.valueOf(TurnType.TSHR, leftSide);
description = ctx.getString(R.string.route_tshr);
} else {
turn = TurnType.valueOf(TurnType.TU, leftSide);
description = ctx.getString(R.string.route_tu);
}
}
}
if(routeInd == 0 || !turn.getValue().equals(TurnType.C)) {
// TODO correlate speed (weight sum) when next turn type is C
TurnType turn = s.getTurnType();
if(turn != null) {
RouteDirectionInfo info = new RouteDirectionInfo(s.getSegmentSpeed(), turn);
info.setDescriptionRoute(description + " " +
OsmAndFormatter.getFormattedDistance(s.getDistance(), ctx));
String description = toString(turn, ctx);
info.setDescriptionRoute(description);
info.routePointOffset = prevLocationSize;
if(directions.size() > 0 && prevDirectionTime > 0 && prevDirectionDistance > 0) {
RouteDirectionInfo prev = directions.get(directions.size() - 1);
prev.setAverageSpeed(prevDirectionDistance / prevDirectionTime);
prev.setDescriptionRoute(prev.getDescriptionRoute() + " " + OsmAndFormatter.getFormattedDistance(prevDirectionDistance, ctx));
prevDirectionDistance = 0;
prevDirectionTime = 0;
}
directions.add(info);
}
prevDirectionDistance += s.getDistance();
prevDirectionTime += s.getSegmentTime();
}
if(directions.size() > 0 && prevDirectionTime > 0 && prevDirectionDistance > 0) {
RouteDirectionInfo prev = directions.get(directions.size() - 1);
prev.setAverageSpeed(prevDirectionDistance / prevDirectionTime);
prev.setDescriptionRoute(prev.getDescriptionRoute() + " " + OsmAndFormatter.getFormattedDistance(prevDirectionDistance, ctx));
}
introduceFirstPoint(start);
updateListDistanceTime();

View file

@ -1,5 +1,7 @@
package net.osmand.plus.routing;
import net.osmand.router.TurnType;
public class RouteDirectionInfo {
// location when you should action (turn or go ahead)
public int routePointOffset;

View file

@ -39,6 +39,7 @@ import net.osmand.router.GeneralRouter.GeneralRouterProfile;
import net.osmand.router.RouteSegmentResult;
import net.osmand.router.RoutingConfiguration;
import net.osmand.router.RoutingContext;
import net.osmand.router.TurnType;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -505,7 +506,7 @@ public class RouteProvider {
return new RouteCalculationResult("End point is far from allowed road.");
}
try {
List<RouteSegmentResult> result = router.searchRoute(ctx, st, en);
List<RouteSegmentResult> result = router.searchRoute(ctx, st, en, leftSide);
return new RouteCalculationResult(result, start, end, app, leftSide);
} catch (OutOfMemoryError e) {
return new RouteCalculationResult("Not enough process memory");

View file

@ -4,6 +4,7 @@ import net.osmand.plus.activities.ApplicationMode;
import net.osmand.plus.voice.AbstractPrologCommandPlayer;
import net.osmand.plus.voice.CommandBuilder;
import net.osmand.plus.voice.CommandPlayer;
import net.osmand.router.TurnType;
import android.content.Context;
import android.location.Location;

View file

@ -8,7 +8,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.TurnType;
import net.osmand.router.TurnType;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;

View file

@ -2,7 +2,7 @@ package net.osmand.plus.views;
import net.osmand.OsmAndFormatter;
import net.osmand.plus.R;
import net.osmand.plus.routing.TurnType;
import net.osmand.router.TurnType;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;

View file

@ -1,7 +1,7 @@
package net.osmand.plus.views;
import net.osmand.plus.R;
import net.osmand.plus.routing.TurnType;
import net.osmand.router.TurnType;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.ColorFilter;