Skip to content

Commit

Permalink
Add combined turn lanes
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanPyrohivskyi committed Jun 27, 2023
1 parent e49b9c7 commit 1a68c6d
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 22 deletions.
151 changes: 130 additions & 21 deletions OsmAnd-java/src/main/java/net/osmand/router/RouteResultPreparation.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -47,6 +46,7 @@ public class RouteResultPreparation {
private static final float TURN_DEGREE_MIN = 45;
private static final float UNMATCHED_TURN_DEGREE_MINIMUM = 45;
private static final float SPLIT_TURN_DEGREE_NOT_STRAIGHT = 100;
private static final float TURN_SLIGHT_DEGREE = 5;
public static final int SHIFT_ID = 6;
protected static final Log LOG = PlatformUtil.getLog(RouteResultPreparation.class);
public static final String UNMATCHED_HIGHWAY_TYPE = "unmatched";
Expand Down Expand Up @@ -1258,7 +1258,6 @@ private int[] getTurnLanesInfo(RouteSegmentResult prevSegm, RouteSegmentResult c
if (hasAllowedLanes(mainTurnType, lanesArray, startIndex, endIndex)) {
for (int k = startIndex; k <= endIndex; k++) {
lanesArray[k] |= 1;
TurnType.getPrimaryTurn(lanesArray[k]);
}
isSet = true;
}
Expand Down Expand Up @@ -1372,6 +1371,16 @@ private class RoadSplitStructure {
int addRoadsOnLeft = 0;
int roadsOnRight = 0;
int addRoadsOnRight = 0;
List<Double> attachedAngles;

public boolean allAreStraight() {
for (double angle : attachedAngles) {
if (Math.abs(angle) > TURN_SLIGHT_DEGREE) {
return false;
}
}
return true;
}
}


Expand Down Expand Up @@ -1509,6 +1518,7 @@ protected RoadSplitStructure calculateRoadSplitStructure(RouteSegmentResult prev
double prevAngle = MapUtils.normalizeDegrees360(prevSegm.getBearingBegin() - 180);
boolean hasSharpOrReverseLane = hasSharpOrReverseTurnLane(turnLanesPrevSegm);
boolean hasSameTurnLanes = hasSameTurnLanes(prevSegm, currentSegm);
rs.attachedAngles = new ArrayList<>();
for (RouteSegmentResult attached : attachedRoutes) {
boolean restricted = false;
for(int k = 0; k < prevSegm.getObject().getRestrictionLength(); k++) {
Expand All @@ -1522,7 +1532,8 @@ protected RoadSplitStructure calculateRoadSplitStructure(RouteSegmentResult prev
continue;
}
double ex = MapUtils.degreesDiff(attached.getBearingBegin(), currentSegm.getBearingBegin());
double mpi = Math.abs(MapUtils.degreesDiff(prevSegm.getBearingEnd(), attached.getBearingBegin()));
double deviation = MapUtils.degreesDiff(prevSegm.getBearingEnd(), attached.getBearingBegin());
double mpi = Math.abs(deviation);
int rsSpeakPriority = highwaySpeakPriority(attached.getObject().getHighway());
int lanes = countLanesMinOne(attached);
int[] turnLanesAttachedRoad = parseTurnLanes(attached.getObject(), attached.getBearingBegin() * Math.PI / 180);
Expand Down Expand Up @@ -1585,6 +1596,7 @@ protected RoadSplitStructure calculateRoadSplitStructure(RouteSegmentResult prev
}
}
}
rs.attachedAngles.add(deviation);
}
return rs;
}
Expand Down Expand Up @@ -1616,40 +1628,137 @@ private boolean foundTUturn(List<Integer> turnList) {

protected TurnType createSimpleKeepLeftRightTurn(boolean leftSide, RouteSegmentResult prevSegm,
RouteSegmentResult currentSegm, RoadSplitStructure rs) {
double devation = Math.abs(MapUtils.degreesDiff(prevSegm.getBearingEnd(), currentSegm.getBearingBegin()));
boolean makeSlightTurn = devation > 5 && (!isMotorway(prevSegm) || !isMotorway(currentSegm));
double deviation = MapUtils.degreesDiff(prevSegm.getBearingEnd(), currentSegm.getBearingBegin());
boolean makeSlightTurn = Math.abs(deviation) > TURN_SLIGHT_DEGREE && (!isMotorway(prevSegm) || !isMotorway(currentSegm));
TurnType t = null;
int laneType = TurnType.C;
if (rs.keepLeft && rs.keepRight) {
t = TurnType.valueOf(TurnType.C, leftSide);
} else if (rs.keepLeft) {
t = TurnType.valueOf(makeSlightTurn ? TurnType.TSLL : TurnType.KL, leftSide);
if (makeSlightTurn) {
laneType = TurnType.TSLL;
}
} else if (rs.keepRight) {
t = TurnType.valueOf(makeSlightTurn ? TurnType.TSLR : TurnType.KR, leftSide);
if (makeSlightTurn) {
} else if (rs.keepLeft || rs.keepRight) {
if (deviation < -TURN_SLIGHT_DEGREE && makeSlightTurn) {
t = TurnType.valueOf(TurnType.TSLR, leftSide);
laneType = TurnType.TSLR;
} else if (deviation > TURN_SLIGHT_DEGREE && makeSlightTurn) {
t = TurnType.valueOf(TurnType.TSLL, leftSide);
laneType = TurnType.TSLL;
} else {
t = TurnType.valueOf(rs.keepLeft ? TurnType.KL : TurnType.KR, leftSide);
}
} else {
return null;
}
int current = countLanesMinOne(currentSegm);
int ls = current + rs.leftLanes + rs.rightLanes;
int[] lanes = new int[ls];
for (int it = 0; it < ls; it++) {
if (it < rs.leftLanes || it >= rs.leftLanes + current) {
lanes[it] = TurnType.C << 1;
} else {
lanes[it] = (laneType << 1) + 1;
int currentLanesCount = countLanesMinOne(currentSegm);
int prevLanesCount = countLanesMinOne(prevSegm);
boolean oneLane = currentLanesCount == 1 && prevLanesCount == 1;
int[] lanes;
if (oneLane) {
lanes = createCombinedSingleLane(rs, deviation);
} else {
int ls = currentLanesCount + rs.leftLanes + rs.rightLanes;
lanes = new int[ls];
for (int it = 0; it < ls; it++) {
if (it < rs.leftLanes) {
//lanes left from active
if (laneType != TurnType.C) {
//avoid repeat of turns, e.g. for TSLL get TL
lanes[it] = TurnType.getPrev(laneType) << 1;
} else {
// can be several straight directions
lanes[it] = TurnType.C << 1;
}
} else if (it >= rs.leftLanes + currentLanesCount) {
//lanes in right from active
if (laneType != TurnType.C) {
lanes[it] = TurnType.getNext(laneType) << 1;
} else {
lanes[it] = TurnType.C << 1;
}
} else {
//active lane
if (currentLanesCount == 1) {
int[] combined = createCombinedSingleLane(rs, deviation);
lanes[it] = combined[0];
} else {
lanes[it] = (laneType << 1) + 1;
}
}
}
}
t.setSkipToSpeak(!rs.speak);
t.setLanes(lanes);
return t;
}

private int[] createCombinedSingleLane(RoadSplitStructure rs, double currentDeviation) {
rs.attachedAngles.add(currentDeviation);
Collections.sort(rs.attachedAngles, new Comparator<Double>() {
@Override
public int compare(Double c1, Double c2) {
return Double.compare(c1, c2);
}
});

int size = rs.attachedAngles.size();
boolean allStraight = rs.allAreStraight();
int[] lanes = new int[1];
int cnt = 0;
//iterate from left to right turns
for (int i = size - 1; i >= 0; i--) {
double angle = rs.attachedAngles.get(i);
int turn;
if (allStraight) {
//create fork intersection
if (i == 0) {
turn = TurnType.KL;
} else if (i == size - 1) {
turn = TurnType.KR;
} else {
turn = TurnType.C;
}
} else {
turn = getTurnByAngle(angle);
}
if (angle == currentDeviation) {
TurnType.setPrimaryTurn(lanes, 0, turn);
continue;
}
switch (cnt) {
case 0:
TurnType.setSecondaryTurn(lanes, 0, turn);
break;
case 1:
TurnType.setTertiaryTurn(lanes, 0, turn);
break;
}
cnt++;
}
lanes[0] |= 1;
return lanes;
}

private int getTurnByAngle(double angle) {
int turnType = TurnType.C;
if (angle < -150) {
turnType = TurnType.TRU;
} else if (angle < -120) {
turnType = TurnType.TSHR;
} else if (angle < -TURN_DEGREE_MIN) {
turnType = TurnType.TR;
} else if (angle <= -TURN_SLIGHT_DEGREE) {
turnType = TurnType.TSLR;
} else if (angle > -TURN_SLIGHT_DEGREE && angle < TURN_SLIGHT_DEGREE) {
turnType = TurnType.C;
} else if (angle < TURN_DEGREE_MIN) {
turnType = TurnType.TSLL;
} else if (angle < 120) {
turnType = TurnType.TL;
} else if (angle < 150) {
turnType = TurnType.TSHL;
} else {
turnType = TurnType.TU;
}
return turnType;
}

protected int countLanesMinOne(RouteSegmentResult attached) {
final boolean oneway = attached.getObject().getOneway() != 0;
Expand Down
20 changes: 19 additions & 1 deletion OsmAnd-java/src/main/java/net/osmand/router/TurnType.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class TurnType {
public static final int OFFR = 12; // Off route //$NON-NLS-1$
public static final int RNDB = 13; // Roundabout
public static final int RNLB = 14; // Roundabout left
private static final int[] TURNS_ORDER = {TU, TSHL, TL, TSLL, C, TSLR, TR, TSHR, TRU};

public static TurnType straight() {
return valueOf(C, false);
Expand Down Expand Up @@ -559,6 +560,23 @@ public static int convertType(String lane) {
return turn;
}


public static int getPrev(int turn) {
for (int i = TURNS_ORDER.length - 1; i >= 0; i--) {
int t = TURNS_ORDER[i];
if (t == turn && i > 0) {
return TURNS_ORDER[i - 1];
}
}
return turn;
}

public static int getNext(int turn) {
for (int i = 0; i < TURNS_ORDER.length; i++) {
int t = TURNS_ORDER[i];
if (t == turn && i + 1 < TURNS_ORDER.length) {
return TURNS_ORDER[i + 1];
}
}
return turn;
}
}

0 comments on commit 1a68c6d

Please sign in to comment.