Merge pull request #952 from saiarcot895/merge-turn-lanes

Implement merging nearby turns together.
This commit is contained in:
vshcherb 2014-12-07 00:46:57 +01:00
commit a2c041274b
2 changed files with 117 additions and 5 deletions

View file

@ -42,7 +42,7 @@ public class RouteResultPreparation {
splitRoadsAndAttachRoadSegments(ctx, result);
// calculate time
calculateTimeSpeed(ctx, result);
addTurnInfo(ctx.leftSideNavigation, result);
return result;
}
@ -391,6 +391,90 @@ public class RouteResultPreparation {
dist += result.get(i).getDistance();
}
}
determineTurnsToMerge(leftside, result);
}
private void determineTurnsToMerge(boolean leftside, List<RouteSegmentResult> result) {
for (int i = result.size() - 2; i >= 0; i--) {
RouteSegmentResult currentSegment = result.get(i);
RouteSegmentResult nextSegment = null;
// We need to get the next segment that has a turn and lanes attached.
for (int j = i + 1; j < result.size(); j++) {
RouteSegmentResult possibleSegment = result.get(j);
if (possibleSegment.getTurnType() != null && possibleSegment.getTurnType().getLanes() != null) {
nextSegment = possibleSegment;
break;
}
}
if (nextSegment == null) {
continue;
}
TurnType currentTurn = currentSegment.getTurnType();
TurnType nextTurn = nextSegment.getTurnType();
if (currentTurn == null || currentTurn.getLanes() == null || nextTurn == null || nextTurn.getLanes() == null) {
continue;
}
// Only allow slight turns that are nearby to be merged.
if (currentSegment.getDistance() < 60 && nextTurn.getLanes().length <= currentTurn.getLanes().length
&& TurnType.isSlightTurn(currentTurn.getValue())) {
mergeTurnLanes(leftside, currentSegment, nextSegment);
}
}
}
private void mergeTurnLanes(boolean leftSide, RouteSegmentResult currentSegment, RouteSegmentResult nextSegment) {
TurnType currentTurn = currentSegment.getTurnType();
TurnType nextTurn = nextSegment.getTurnType();
boolean isUsingTurnLanes = TurnType.getPrimaryTurn(currentTurn.getLanes()[0]) != 0
&& TurnType.getPrimaryTurn(nextTurn.getLanes()[0]) != 0;
if (isUsingTurnLanes) {
int[] lanes = new int[currentTurn.getLanes().length];
// Unset the allowed lane bit
for (int i = 0; i < lanes.length; i++) {
lanes[i] = currentTurn.getLanes()[i] & ~1;
}
// Find the first lane that matches (based on the turn being taken), and how many lanes match
int matchingIndex = 0;
int maxMatchedLanes = 0;
for (int i = 0; i < lanes.length; i++) {
int matchedLanes = 0;
for (int j = 0; j < nextTurn.getLanes().length - i; j++) {
if (TurnType.getPrimaryTurn(nextTurn.getLanes()[j])
== TurnType.getPrimaryTurn(currentTurn.getLanes()[i + j])) {
matchedLanes++;
} else {
break;
}
}
if (matchedLanes > maxMatchedLanes) {
matchingIndex = i;
maxMatchedLanes = matchedLanes;
}
}
if (maxMatchedLanes <= 1) {
return;
}
// Copy the allowed bit from the next segment's lanes to the current segment's matching lanes
for (int i = matchingIndex; i - matchingIndex < nextTurn.getLanes().length; i++) {
lanes[i] |= nextTurn.getLanes()[i - matchingIndex] & 1;
}
currentTurn.setLanes(lanes);
int turn = inferTurnFromLanes(lanes);
if (turn != 0 && turn != currentTurn.getValue()) {
TurnType newTurnType = TurnType.valueOf(turn, leftSide);
newTurnType.setLanes(lanes);
newTurnType.setSkipToSpeak(currentTurn.isSkipToSpeak());
currentSegment.setTurnType(newTurnType);
}
}
}
private static final int MAX_SPEAK_PRIORITY = 5;
@ -563,6 +647,7 @@ public class RouteResultPreparation {
int right = 0;
boolean speak = false;
int speakPriority = Math.max(highwaySpeakPriority(prevSegm.getObject().getHighway()), highwaySpeakPriority(currentSegm.getObject().getHighway()));
boolean otherRoutesExist = false;
if (attachedRoutes != null) {
for (RouteSegmentResult attached : attachedRoutes) {
double ex = MapUtils.degreesDiff(attached.getBearingBegin(), currentSegm.getBearingBegin());
@ -577,6 +662,9 @@ public class RouteResultPreparation {
kr = true;
left += countLanesMinOne(attached);
speak = speak || rsSpeakPriority <= speakPriority;
} else if (mpi >= TURN_DEGREE_MIN) {
// Indicate that there are other turns at this intersection, and displaying the lanes may be helpful here.
otherRoutesExist = true;
}
}
}
@ -603,13 +691,33 @@ public class RouteResultPreparation {
double devation = Math.abs(MapUtils.degreesDiff(prevSegm.getBearingEnd(), currentSegm.getBearingBegin()));
boolean makeSlightTurn = devation > 5 && (!isMotorway(prevSegm) || !isMotorway(currentSegm));
if (kl) {
if (kl && kr) {
t = TurnType.valueOf(TurnType.C, leftSide);
t.setSkipToSpeak(!speak);
} else if (kl) {
t = TurnType.valueOf(makeSlightTurn ? TurnType.TSLL : TurnType.KL, leftSide);
t.setSkipToSpeak(!speak);
}
if (kr) {
} else if (kr) {
t = TurnType.valueOf(makeSlightTurn ? TurnType.TSLR : TurnType.KR, leftSide);
t.setSkipToSpeak(!speak);
} else if (otherRoutesExist && getTurnLanesString(prevSegm) != null) {
// Maybe going straight at a 90-degree intersection
t = TurnType.valueOf(TurnType.C, leftSide);
t.setSkipToSpeak(true);
// When going straight, the lanes have to be calculated from the previous segment, not the current/next segment.
int prevLanes = countLanesMinOne(prevSegm);
t.setLanes(attachTurnLanesData(prevSegm, new int[prevLanes]));
// Manually set the allowed lanes based on the turn type
for (int i = 0; i < t.getLanes().length; i++) {
if (TurnType.getPrimaryTurn(t.getLanes()[i]) == TurnType.C) {
t.getLanes()[i] |= 1;
}
}
return t;
}
if (t != null && lanes != null) {
int[] calcLanes = attachTurnLanesData(prevSegm, lanes);

View file

@ -253,4 +253,8 @@ public class TurnType {
public static boolean isRightTurn(int type) {
return type == TR || type == TSHR || type == TSLR;
}
}
public static boolean isSlightTurn(int type) {
return type == TSLL || type == TSLR || type == C || type == KL || type == KR;
}
}