This commit is contained in:
Victor Shcherb 2020-06-10 18:25:43 +02:00
parent 96053e81b0
commit 2223d9918e
3 changed files with 98 additions and 97 deletions

View file

@ -1,6 +1,24 @@
package net.osmand.router; package net.osmand.router;
import net.osmand.NativeLibrary; import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import gnu.trove.iterator.TIntIterator;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.set.hash.TIntHashSet;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.binary.BinaryMapIndexReader; import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule; import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
@ -19,26 +37,6 @@ import net.osmand.util.Algorithms;
import net.osmand.util.MapAlgorithms; import net.osmand.util.MapAlgorithms;
import net.osmand.util.MapUtils; import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import gnu.trove.iterator.TIntIterator;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.set.hash.TIntHashSet;
public class RouteResultPreparation { public class RouteResultPreparation {
public static boolean PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = false; public static boolean PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = false;
@ -623,7 +621,7 @@ public class RouteResultPreparation {
// calculateStatistics(result); // calculateStatistics(result);
} }
private void calculateStatistics(List<RouteSegmentResult> result) { protected void calculateStatistics(List<RouteSegmentResult> result) {
InputStream is = RenderingRulesStorage.class.getResourceAsStream("default.render.xml"); InputStream is = RenderingRulesStorage.class.getResourceAsStream("default.render.xml");
final Map<String, String> renderingConstants = new LinkedHashMap<String, String>(); final Map<String, String> renderingConstants = new LinkedHashMap<String, String>();
try { try {
@ -800,13 +798,22 @@ public class RouteResultPreparation {
} }
if (dist < mergeDistance) { if (dist < mergeDistance) {
mergeTurnLanes(leftside, currentSegment, nextSegment); mergeTurnLanes(leftside, currentSegment, nextSegment);
inferCommonActiveLane(currentSegment.getTurnType(), nextSegment.getTurnType()); TurnType turnType = currentSegment.getTurnType();
TIntHashSet possibleTurn = getPossibleTurnsFromActiveLanes(turnType.getLanes(), true);
if (possibleTurn.size() == 1) {
TurnType tt = TurnType.valueOf(possibleTurn.iterator().next(), currentSegment.getTurnType().isLeftSide());
tt.setLanes(turnType.getLanes());
tt.setSkipToSpeak(turnType.isSkipToSpeak());
currentSegment.setTurnType(tt);
turnType = tt;
}
inferCommonActiveLane(turnType, nextSegment.getTurnType());
merged = true; merged = true;
} }
} }
if (!merged) { if (!merged) {
TurnType tt = currentSegment.getTurnType(); TurnType tt = currentSegment.getTurnType();
inferActiveTurnLanesFromTurn(tt, TurnType.C); inferActiveTurnLanesFromTurn(tt, tt.getValue());
} }
nextSegment = currentSegment; nextSegment = currentSegment;
dist = 0; dist = 0;
@ -984,11 +991,9 @@ public class RouteResultPreparation {
if(turnSet.size() == 1) { if(turnSet.size() == 1) {
singleTurn = turnSet.iterator().next(); singleTurn = turnSet.iterator().next();
} else if(currentTurn.goAhead() && turnSet.contains(nextTurn.getValue())) { } else if(currentTurn.goAhead() && turnSet.contains(nextTurn.getValue())) {
if(currentTurn.isPossibleLeftTurn() && if (currentTurn.isPossibleLeftTurn() && TurnType.isLeftTurn(nextTurn.getValue())) {
TurnType.isLeftTurn(nextTurn.getValue())) {
singleTurn = nextTurn.getValue(); singleTurn = nextTurn.getValue();
} else if(currentTurn.isPossibleLeftTurn() && } else if (currentTurn.isPossibleLeftTurn() && TurnType.isLeftTurn(nextTurn.getActiveCommonLaneTurn())) {
TurnType.isLeftTurn(nextTurn.getActiveCommonLaneTurn())) {
singleTurn = nextTurn.getActiveCommonLaneTurn(); singleTurn = nextTurn.getActiveCommonLaneTurn();
} else if(currentTurn.isPossibleRightTurn() && } else if(currentTurn.isPossibleRightTurn() &&
TurnType.isRightTurn(nextTurn.getValue())) { TurnType.isRightTurn(nextTurn.getValue())) {
@ -1054,7 +1059,7 @@ public class RouteResultPreparation {
// add description about turn // add description about turn
double mpi = MapUtils.degreesDiff(prev.getBearingEnd(), rr.getBearingBegin()); double mpi = MapUtils.degreesDiff(prev.getBearingEnd(), rr.getBearingBegin());
if(noAttachedRoads){ if(noAttachedRoads){
// TODO VICTOR : look at the comment inside direction route // VICTOR : look at the comment inside direction route
// ? avoid small zigzags is covered at (search for "zigzags") // ? avoid small zigzags is covered at (search for "zigzags")
// double begin = rr.getObject().directionRoute(rr.getStartPointIndex(), rr.getStartPointIndex() < // double begin = rr.getObject().directionRoute(rr.getStartPointIndex(), rr.getStartPointIndex() <
// rr.getEndPointIndex(), 25); // rr.getEndPointIndex(), 25);
@ -1269,17 +1274,8 @@ public class RouteResultPreparation {
String[] splitLaneOptions = turnLanes.split("\\|", -1); String[] splitLaneOptions = turnLanes.split("\\|", -1);
int activeBeginIndex = findActiveIndex(rawLanes, splitLaneOptions, rs.leftLanes, true, int activeBeginIndex = findActiveIndex(rawLanes, splitLaneOptions, rs.leftLanes, true,
rs.leftLanesInfo, rs.roadsOnLeft, rs.addRoadsOnLeft); rs.leftLanesInfo, rs.roadsOnLeft, rs.addRoadsOnLeft);
if(!rs.keepLeft && activeBeginIndex != -1 &&
splitLaneOptions.length > 0 && !splitLaneOptions[splitLaneOptions.length - 1].contains(";")) {
activeBeginIndex = Math.max(activeBeginIndex, 1);
}
int activeEndIndex = findActiveIndex(rawLanes, splitLaneOptions, rs.rightLanes, false, int activeEndIndex = findActiveIndex(rawLanes, splitLaneOptions, rs.rightLanes, false,
rs.rightLanesInfo, rs.roadsOnRight, rs.addRoadsOnRight); rs.rightLanesInfo, rs.roadsOnRight, rs.addRoadsOnRight);
if(!rs.keepRight && activeEndIndex != -1 &&
splitLaneOptions.length > 0 && !splitLaneOptions[0].contains(";") ) {
activeEndIndex = Math.min(activeEndIndex, rawLanes.length - 1);
}
if (activeBeginIndex == -1 || activeEndIndex == -1 || activeBeginIndex > activeEndIndex) { if (activeBeginIndex == -1 || activeEndIndex == -1 || activeBeginIndex > activeEndIndex) {
// something went wrong // something went wrong
return createSimpleKeepLeftRightTurn(leftSide, prevSegm, currentSegm, rs); return createSimpleKeepLeftRightTurn(leftSide, prevSegm, currentSegm, rs);
@ -1292,6 +1288,12 @@ public class RouteResultPreparation {
int tp = inferSlightTurnFromLanes(rawLanes, rs); int tp = inferSlightTurnFromLanes(rawLanes, rs);
if (tp != t.getValue() && tp != 0) { if (tp != t.getValue() && tp != 0) {
t = TurnType.valueOf(tp, leftSide); t = TurnType.valueOf(tp, leftSide);
} else {
if (rs.keepRight && TurnType.getSecondaryTurn(rawLanes[activeEndIndex]) == 0) {
t = TurnType.valueOf(TurnType.getPrimaryTurn(rawLanes[activeEndIndex]), leftSide);
} else if (rs.keepLeft && TurnType.getSecondaryTurn(rawLanes[activeBeginIndex]) == 0) {
t = TurnType.valueOf(TurnType.getPrimaryTurn(rawLanes[activeBeginIndex]), leftSide);
}
} }
} else { } else {
for (int k = 0; k < rawLanes.length; k++) { for (int k = 0; k < rawLanes.length; k++) {
@ -1597,59 +1599,11 @@ public class RouteResultPreparation {
} }
private int inferSlightTurnFromLanes(int[] oLanes, RoadSplitStructure rs) { private int inferSlightTurnFromLanes(int[] oLanes, RoadSplitStructure rs) {
TIntHashSet possibleTurns = new TIntHashSet(); TIntHashSet possibleTurns = getPossibleTurnsFromActiveLanes(oLanes, false);
for (int i = 0; i < oLanes.length; i++) { if (possibleTurns.isEmpty()) {
if ((oLanes[i] & 1) == 0) { // No common turns, so can't determine anything.
continue; return 0;
}
if (possibleTurns.isEmpty()) {
// Nothing is in the list to compare to, so add the first elements
possibleTurns.add(TurnType.getPrimaryTurn(oLanes[i]));
if (TurnType.getSecondaryTurn(oLanes[i]) != 0) {
possibleTurns.add(TurnType.getSecondaryTurn(oLanes[i]));
}
if (TurnType.getTertiaryTurn(oLanes[i]) != 0) {
possibleTurns.add(TurnType.getTertiaryTurn(oLanes[i]));
}
} else {
TIntArrayList laneTurns = new TIntArrayList();
laneTurns.add(TurnType.getPrimaryTurn(oLanes[i]));
if (TurnType.getSecondaryTurn(oLanes[i]) != 0) {
laneTurns.add(TurnType.getSecondaryTurn(oLanes[i]));
}
if (TurnType.getTertiaryTurn(oLanes[i]) != 0) {
laneTurns.add(TurnType.getTertiaryTurn(oLanes[i]));
}
possibleTurns.retainAll(laneTurns);
if (possibleTurns.isEmpty()) {
// No common turns, so can't determine anything.
return 0;
}
}
} }
// Remove all turns from lanes not selected...because those aren't it
for (int i = 0; i < oLanes.length; i++) {
if ((oLanes[i] & 1) == 0 && !possibleTurns.isEmpty()) {
possibleTurns.remove((Integer) TurnType.getPrimaryTurn(oLanes[i]));
if (TurnType.getSecondaryTurn(oLanes[i]) != 0) {
possibleTurns.remove((Integer) TurnType.getSecondaryTurn(oLanes[i]));
}
if (TurnType.getTertiaryTurn(oLanes[i]) != 0) {
possibleTurns.remove((Integer) TurnType.getTertiaryTurn(oLanes[i]));
}
}
}
// remove all non-slight turns // TEST don't pass
// if(possibleTurns.size() > 1) {
// TIntIterator it = possibleTurns.iterator();
// while(it.hasNext()) {
// int nxt = it.next();
// if(!TurnType.isSlightTurn(nxt)) {
// it.remove();
// }
// }
// }
int infer = 0; int infer = 0;
if (possibleTurns.size() == 1) { if (possibleTurns.size() == 1) {
infer = possibleTurns.iterator().next(); infer = possibleTurns.iterator().next();
@ -1688,6 +1642,53 @@ public class RouteResultPreparation {
return infer; return infer;
} }
private TIntHashSet getPossibleTurnsFromActiveLanes(int[] oLanes, boolean onlyPrimary) {
TIntHashSet possibleTurns = new TIntHashSet();
for (int i = 0; i < oLanes.length; i++) {
if ((oLanes[i] & 1) == 0) {
continue;
}
if (possibleTurns.isEmpty()) {
// Nothing is in the list to compare to, so add the first elements
possibleTurns.add(TurnType.getPrimaryTurn(oLanes[i]));
if (!onlyPrimary && TurnType.getSecondaryTurn(oLanes[i]) != 0) {
possibleTurns.add(TurnType.getSecondaryTurn(oLanes[i]));
}
if (!onlyPrimary && TurnType.getTertiaryTurn(oLanes[i]) != 0) {
possibleTurns.add(TurnType.getTertiaryTurn(oLanes[i]));
}
} else {
TIntArrayList laneTurns = new TIntArrayList();
laneTurns.add(TurnType.getPrimaryTurn(oLanes[i]));
if (!onlyPrimary && TurnType.getSecondaryTurn(oLanes[i]) != 0) {
laneTurns.add(TurnType.getSecondaryTurn(oLanes[i]));
}
if (!onlyPrimary && TurnType.getTertiaryTurn(oLanes[i]) != 0) {
laneTurns.add(TurnType.getTertiaryTurn(oLanes[i]));
}
possibleTurns.retainAll(laneTurns);
if (possibleTurns.isEmpty()) {
// No common turns, so can't determine anything.
return possibleTurns;
}
}
}
// Remove all turns from lanes not selected...because those aren't it
for (int i = 0; i < oLanes.length; i++) {
if ((oLanes[i] & 1) == 0 && !possibleTurns.isEmpty()) {
possibleTurns.remove((Integer) TurnType.getPrimaryTurn(oLanes[i]));
if (TurnType.getSecondaryTurn(oLanes[i]) != 0) {
possibleTurns.remove((Integer) TurnType.getSecondaryTurn(oLanes[i]));
}
if (TurnType.getTertiaryTurn(oLanes[i]) != 0) {
possibleTurns.remove((Integer) TurnType.getTertiaryTurn(oLanes[i]));
}
}
}
return possibleTurns;
}
private boolean isMotorway(RouteSegmentResult s){ private boolean isMotorway(RouteSegmentResult s){
String h = s.getObject().getHighway(); String h = s.getObject().getHighway();
return "motorway".equals(h) || "motorway_link".equals(h) || return "motorway".equals(h) || "motorway_link".equals(h) ||

View file

@ -21,6 +21,8 @@ import gnu.trove.map.hash.TIntObjectHashMap;
public class RouteSegmentResult implements StringExternalizable<RouteDataBundle> { public class RouteSegmentResult implements StringExternalizable<RouteDataBundle> {
// this should be bigger (50-80m) but tests need to be fixed first
private static final float DIST_BEARING_DETECT = 5;
private final RouteDataObject object; private final RouteDataObject object;
private int startPointIndex; private int startPointIndex;
private int endPointIndex; private int endPointIndex;
@ -444,11 +446,11 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
} }
public float getBearingBegin() { public float getBearingBegin() {
return (float) (object.directionRoute(startPointIndex, startPointIndex < endPointIndex) / Math.PI * 180); return (float) (object.directionRoute(startPointIndex, startPointIndex < endPointIndex, DIST_BEARING_DETECT) / Math.PI * 180);
} }
public float getBearing(int point, boolean plus) { public float getBearing(int point, boolean plus) {
return (float) (object.directionRoute(point, plus) / Math.PI * 180); return (float) (object.directionRoute(point, plus, DIST_BEARING_DETECT) / Math.PI * 180);
} }
public float getDistance(int point, boolean plus) { public float getDistance(int point, boolean plus) {
@ -456,7 +458,7 @@ public class RouteSegmentResult implements StringExternalizable<RouteDataBundle>
} }
public float getBearingEnd() { public float getBearingEnd() {
return (float) (MapUtils.alignAngleDifference(object.directionRoute(endPointIndex, startPointIndex > endPointIndex) - Math.PI) / Math.PI * 180); return (float) (MapUtils.alignAngleDifference(object.directionRoute(endPointIndex, startPointIndex > endPointIndex, DIST_BEARING_DETECT) - Math.PI) / Math.PI * 180);
} }
public void setSegmentTime(float segmentTime) { public void setSegmentTime(float segmentTime) {

View file

@ -38,15 +38,13 @@ public class RouteResultPreparationTest {
private static RoutePlannerFrontEnd fe; private static RoutePlannerFrontEnd fe;
private static RoutingContext ctx; private static RoutingContext ctx;
private String testName;
private LatLon startPoint; private LatLon startPoint;
private LatLon endPoint; private LatLon endPoint;
private Map<Long, String> expectedResults; private Map<Long, String> expectedResults;
private Log log = PlatformUtil.getLog(RouteResultPreparationTest.class); protected Log log = PlatformUtil.getLog(RouteResultPreparationTest.class);
public RouteResultPreparationTest(String testName, LatLon startPoint, LatLon endPoint, Map<Long, String> expectedResults) { public RouteResultPreparationTest(String testName, LatLon startPoint, LatLon endPoint, Map<Long, String> expectedResults) {
this.testName = testName;
this.startPoint = startPoint; this.startPoint = startPoint;
this.endPoint = endPoint; this.endPoint = endPoint;
this.expectedResults = expectedResults; this.expectedResults = expectedResults;