Adjust route planner
This commit is contained in:
parent
ca090e9a74
commit
7e5601c0d8
6 changed files with 231 additions and 217 deletions
|
@ -30,6 +30,7 @@ public class BinaryRoutePlanner {
|
|||
|
||||
private static final int ROUTE_POINTS = 11;
|
||||
private static final float TURN_DEGREE_MIN = 45;
|
||||
private static final boolean TRACE_ROUTING = false;
|
||||
|
||||
|
||||
private static double squareRootDist(int x1, int y1, int x2, int y2) {
|
||||
|
@ -298,10 +299,10 @@ public class BinaryRoutePlanner {
|
|||
(graphDirectSegments.size() +
|
||||
graphReverseSegments.size()) * STANDARD_ROAD_IN_QUEUE_OVERHEAD;
|
||||
|
||||
|
||||
// String pr = " pend="+segment.parentSegmentEnd +" " +( segment.parentRoute == null ? "" : (" parent=" + segment.parentRoute.road));
|
||||
// System.out.println("Seg " + segment.road + " ind=" + segment.segmentStart +
|
||||
// " ds=" + ((float)segment.distanceFromStart) + " es="+((float)segment.distanceToEnd) + pr);
|
||||
if(TRACE_ROUTING){
|
||||
System.out.print(">");
|
||||
printRoad(segment);
|
||||
}
|
||||
if(segment instanceof FinalRouteSegment) {
|
||||
if(RoutingContext.SHOW_GC_SIZE){
|
||||
log.warn("Estimated overhead " + (ctx.memoryOverhead / (1<<20))+ " mb");
|
||||
|
@ -317,16 +318,16 @@ public class BinaryRoutePlanner {
|
|||
throw new IllegalStateException("There is no enough memory " + ctx.config.memoryLimitation/(1<<20) + " Mb");
|
||||
}
|
||||
ctx.visitedSegments++;
|
||||
// for debug purposes
|
||||
if (ctx.visitor != null) {
|
||||
ctx.visitor.visitSegment(segment, true);
|
||||
}
|
||||
if (!inverse) {
|
||||
processRouteSegment(ctx, false, graphDirectSegments, visitedDirectSegments, targetEndX, targetEndY,
|
||||
segment, visitedOppositeSegments);
|
||||
segment, visitedOppositeSegments, true);
|
||||
processRouteSegment(ctx, false, graphDirectSegments, visitedDirectSegments, targetEndX, targetEndY,
|
||||
segment, visitedOppositeSegments, false);
|
||||
} else {
|
||||
processRouteSegment(ctx, true, graphReverseSegments, visitedOppositeSegments, startX, startY, segment,
|
||||
visitedDirectSegments);
|
||||
visitedDirectSegments, true);
|
||||
processRouteSegment(ctx, true, graphReverseSegments, visitedOppositeSegments, startX, startY, segment,
|
||||
visitedDirectSegments, false);
|
||||
}
|
||||
if(graphReverseSegments.isEmpty()){
|
||||
throw new IllegalArgumentException("Route is not found to selected target point.");
|
||||
|
@ -372,10 +373,21 @@ public class BinaryRoutePlanner {
|
|||
|
||||
|
||||
|
||||
private void printRoad(RouteSegment segment) {
|
||||
String pr;
|
||||
if(segment.parentRoute != null){
|
||||
pr = " pend="+segment.parentSegmentEnd +" parent=" + segment.parentRoute.road;
|
||||
} else {
|
||||
pr = "";
|
||||
}
|
||||
System.out.println("" + segment.road + " ind=" + segment.getSegmentStart() +
|
||||
" ds=" + ((float)segment.distanceFromStart) + " es="+((float)segment.distanceToEnd) + pr);
|
||||
}
|
||||
|
||||
private void relaxNotNeededSegments(RoutingContext ctx, PriorityQueue<RouteSegment> graphSegments, boolean inverse) {
|
||||
// relax strategy is incorrect if we already found a route but it is very long due to some obstacles
|
||||
RouteSegment next = graphSegments.peek();
|
||||
double mine = next.distanceToEnd;
|
||||
double mine = next.distanceFromStart;
|
||||
// int before = graphSegments.size();
|
||||
// SegmentStat statStart = new SegmentStat("Distance from start (" + inverse + ") ");
|
||||
// SegmentStat statEnd = new SegmentStat("Distance to end (" + inverse + ") ");
|
||||
|
@ -388,13 +400,15 @@ public class BinaryRoutePlanner {
|
|||
mine = s.distanceToEnd;
|
||||
}
|
||||
}
|
||||
double d = mine * ctx.config.RELAX_NODES_IF_START_DIST_COEF;
|
||||
iterator = graphSegments.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
RouteSegment s = iterator.next();
|
||||
if (s.distanceToEnd > d) {
|
||||
ctx.relaxedSegments++;
|
||||
iterator.remove();
|
||||
double d = mine + 5000; // ctx.config.RELAX_NODES_IF_START_DIST_COEF;
|
||||
if (d > 0) {
|
||||
iterator = graphSegments.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
RouteSegment s = iterator.next();
|
||||
if (s.distanceToEnd > d) {
|
||||
ctx.relaxedSegments++;
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
// int after = graphSegments.size();
|
||||
|
@ -443,185 +457,80 @@ public class BinaryRoutePlanner {
|
|||
printInfo("Loaded tiles " + ctx.loadedTiles + " (distinct "+ctx.distinctLoadedTiles+ "), unloaded tiles " + ctx.unloadedTiles +
|
||||
", loaded more than once same tiles "
|
||||
+ ctx.loadedPrevUnloadedTiles );
|
||||
printInfo("Visited roads, " + ctx.visitedSegments + ", relaxed roads " + ctx.relaxedSegments);
|
||||
printInfo("Visited roads " + ctx.visitedSegments + ", relaxed roads " + ctx.relaxedSegments);
|
||||
if (graphDirectSegments != null && graphReverseSegments != null) {
|
||||
printInfo("Priority queues sizes : " + graphDirectSegments.size() + "/" + graphReverseSegments.size());
|
||||
}
|
||||
if (visitedDirectSegments != null && visitedOppositeSegments != null) {
|
||||
printInfo("Visited segments sizes: " + visitedDirectSegments.size() + "/" + visitedOppositeSegments.size());
|
||||
printInfo("Visited interval sizes: " + visitedDirectSegments.size() + "/" + visitedOppositeSegments.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void processRouteSegment(final RoutingContext ctx, boolean reverseWaySearch,
|
||||
PriorityQueue<RouteSegment> graphSegments, TLongObjectHashMap<RouteSegment> visitedSegments, int targetEndX, int targetEndY,
|
||||
RouteSegment segment, TLongObjectHashMap<RouteSegment> oppositeSegments) throws IOException {
|
||||
// Always start from segmentStart (!), not from segmentEnd
|
||||
// It makes difference only for the first start segment
|
||||
// Middle point will always be skipped from observation considering already visited
|
||||
RouteSegment segment, TLongObjectHashMap<RouteSegment> oppositeSegments, boolean direction) throws IOException {
|
||||
final RouteDataObject road = segment.road;
|
||||
final int middle = segment.getSegmentStart();
|
||||
float obstaclePlusTime = 0;
|
||||
float obstacleMinusTime = 0;
|
||||
|
||||
|
||||
int oneway = ctx.getRouter().isOneWay(road);
|
||||
boolean minusAllowed;
|
||||
boolean plusAllowed;
|
||||
// use positive direction as agreed
|
||||
if(ctx.firstRoadId == calculateRoutePointId(road, middle, true) ) {
|
||||
minusAllowed = ctx.firstRoadDirection <= 0;
|
||||
plusAllowed = ctx.firstRoadDirection >= 0;
|
||||
} else if (!reverseWaySearch) {
|
||||
minusAllowed = oneway <= 0;
|
||||
plusAllowed = oneway >= 0;
|
||||
} else {
|
||||
minusAllowed = oneway >= 0;
|
||||
plusAllowed = oneway <= 0;
|
||||
}
|
||||
if(middle == road.getPointsLength() - 1 ||
|
||||
visitedSegments.containsKey(calculateRoutePointId(road, middle, true)) ||
|
||||
segment.getAllowedDirection() == -1) {
|
||||
plusAllowed = false;
|
||||
}
|
||||
if(middle == 0 || visitedSegments.containsKey(calculateRoutePointId(road, middle - 1, false)) ||
|
||||
segment.getAllowedDirection() == 1) {
|
||||
minusAllowed = false;
|
||||
}
|
||||
|
||||
// +/- diff from middle point
|
||||
int d = plusAllowed ? 1 : -1;
|
||||
if(segment.getParentRoute() != null) {
|
||||
if(plusAllowed && middle < segment.getRoad().getPointsLength() - 1) {
|
||||
obstaclePlusTime = (float) ctx.getRouter().calculateTurnTime(segment, segment.getRoad().getPointsLength() - 1,
|
||||
segment.getParentRoute(), segment.getParentSegmentEnd());
|
||||
}
|
||||
if(minusAllowed && middle > 0) {
|
||||
obstacleMinusTime = (float) ctx.getRouter().calculateTurnTime(segment, 0,
|
||||
segment.getParentRoute(), segment.getParentSegmentEnd());
|
||||
}
|
||||
}
|
||||
boolean initDirectionAllowed = checkIfInitialMovementAllowedOnSegment(ctx, reverseWaySearch, visitedSegments, segment, direction, road);
|
||||
boolean directionAllowed = initDirectionAllowed;
|
||||
// Go through all point of the way and find ways to continue
|
||||
// ! Actually there is small bug when there is restriction to move forward on the way (it doesn't take into account)
|
||||
float posSegmentDist = 0;
|
||||
float negSegmentDist = 0;
|
||||
while (minusAllowed || plusAllowed) {
|
||||
// 1. calculate point not equal to middle
|
||||
// (algorithm should visit all point on way if it is not oneway)
|
||||
int segmentEnd = middle + d;
|
||||
boolean positive = d > 0;
|
||||
// calculate d for next iteration
|
||||
if (!minusAllowed && d > 0) {
|
||||
d++;
|
||||
} else if (!plusAllowed && d < 0) {
|
||||
d--;
|
||||
float obstaclesTime = 0;
|
||||
if(segment.getParentRoute() != null && directionAllowed) {
|
||||
obstaclesTime = (float) ctx.getRouter().calculateTurnTime(segment, direction? segment.getRoad().getPointsLength() - 1 : 0,
|
||||
segment.getParentRoute(), segment.getParentSegmentEnd());
|
||||
}
|
||||
float segmentDist = 0;
|
||||
// +/- diff from middle point
|
||||
int segmentEnd = segment.getSegmentStart();
|
||||
while (directionAllowed) {
|
||||
int prevInd = segmentEnd;
|
||||
if(direction) {
|
||||
segmentEnd ++;
|
||||
} else {
|
||||
if (d <= 0) {
|
||||
d = -d + 1;
|
||||
} else {
|
||||
d = -d;
|
||||
}
|
||||
segmentEnd --;
|
||||
}
|
||||
if (segmentEnd < 0) {
|
||||
minusAllowed = false;
|
||||
if (segmentEnd < 0 || segmentEnd >= road.getPointsLength()) {
|
||||
directionAllowed = false;
|
||||
continue;
|
||||
}
|
||||
if (segmentEnd >= road.getPointsLength()) {
|
||||
plusAllowed = false;
|
||||
continue;
|
||||
}
|
||||
int intervalId = positive ? segmentEnd - 1 : segmentEnd;
|
||||
long nds = calculateRoutePointId(road, intervalId, positive);
|
||||
visitedSegments.put(nds, segment);
|
||||
RouteSegment opposite = null;
|
||||
// check if that segment was already visited in different direction
|
||||
long opp = calculateRoutePointId(road, intervalId, !positive);
|
||||
if (oppositeSegments.containsKey(opp)) {
|
||||
opposite = oppositeSegments.get(opp);
|
||||
if (opposite.getSegmentStart() != segmentEnd) {
|
||||
opposite = null;
|
||||
}
|
||||
}
|
||||
final int intervalId = direction ? segmentEnd - 1 : segmentEnd;
|
||||
visitedSegments.put(calculateRoutePointId(road, intervalId, direction), segment);
|
||||
|
||||
|
||||
// 2. calculate point and try to load neighbor ways if they are not loaded
|
||||
int x = road.getPoint31XTile(segmentEnd);
|
||||
int y = road.getPoint31YTile(segmentEnd);
|
||||
if(positive) {
|
||||
posSegmentDist += squareRootDist(x, y,
|
||||
road.getPoint31XTile(segmentEnd - 1), road.getPoint31YTile(segmentEnd - 1));
|
||||
} else {
|
||||
negSegmentDist += squareRootDist(x, y,
|
||||
road.getPoint31XTile(segmentEnd + 1), road.getPoint31YTile(segmentEnd + 1));
|
||||
final int x = road.getPoint31XTile(segmentEnd);
|
||||
final int y = road.getPoint31YTile(segmentEnd);
|
||||
final int prevx = road.getPoint31XTile(prevInd);
|
||||
final int prevy = road.getPoint31YTile(prevInd);
|
||||
if(x == prevx && y == prevy) {
|
||||
continue;
|
||||
}
|
||||
// 2. calculate point and try to load neighbor ways if they are not loaded
|
||||
segmentDist += squareRootDist(x, y, prevx, prevy);
|
||||
|
||||
// 2.1 calculate possible obstacle plus time
|
||||
if(positive){
|
||||
double obstacle = ctx.getRouter().defineRoutingObstacle(road, segmentEnd);
|
||||
if (obstacle < 0) {
|
||||
plusAllowed = false;
|
||||
continue;
|
||||
}
|
||||
obstaclePlusTime += obstacle;
|
||||
} else {
|
||||
double obstacle = ctx.getRouter().defineRoutingObstacle(road, segmentEnd);
|
||||
if (obstacle < 0) {
|
||||
minusAllowed = false;
|
||||
continue;
|
||||
}
|
||||
obstacleMinusTime += obstacle;
|
||||
double obstacle = ctx.getRouter().defineRoutingObstacle(road, segmentEnd);
|
||||
if (obstacle < 0) {
|
||||
directionAllowed = false;
|
||||
continue;
|
||||
}
|
||||
obstaclesTime += obstacle;
|
||||
|
||||
boolean alreadyVisited = checkIfOppositieSegmentWasVisited(ctx, reverseWaySearch, graphSegments, segment, oppositeSegments, road,
|
||||
segmentEnd, direction, intervalId, segmentDist, obstaclesTime);
|
||||
if (alreadyVisited) {
|
||||
directionAllowed = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// could be expensive calculation
|
||||
RouteSegment next = ctx.loadRouteSegment(x, y, ctx.config.memoryLimitation - ctx.memoryOverhead);
|
||||
// 3. get intersected ways
|
||||
if (next != null || opposite != null) {
|
||||
// Using A* routing algorithm
|
||||
// g(x) - calculate distance to that point and calculate time
|
||||
|
||||
float priority = ctx.getRouter().defineSpeedPriority(road);
|
||||
float speed = (ctx.getRouter().defineSpeed(road) * priority);
|
||||
if (speed == 0) {
|
||||
speed = (ctx.getRouter().getMinDefaultSpeed() * priority);
|
||||
}
|
||||
// speed can not exceed max default speed according to A*
|
||||
if(speed > ctx.getRouter().getMaxDefaultSpeed()) {
|
||||
speed = ctx.getRouter().getMaxDefaultSpeed();
|
||||
}
|
||||
float distOnRoadToPass = positive? posSegmentDist : negSegmentDist;
|
||||
float distStartObstacles = segment.distanceFromStart + ( positive ? obstaclePlusTime : obstacleMinusTime) +
|
||||
distOnRoadToPass / speed;
|
||||
|
||||
if(opposite != null) {
|
||||
FinalRouteSegment frs = new FinalRouteSegment(road, segment.getSegmentStart());
|
||||
frs.setParentRoute(segment.getParentRoute());
|
||||
frs.setParentSegmentEnd(segment.getParentSegmentEnd());
|
||||
frs.reverseWaySearch = reverseWaySearch;
|
||||
frs.distanceFromStart = opposite.distanceFromStart + distStartObstacles;
|
||||
frs.distanceToEnd = 0;
|
||||
frs.opposite = opposite;
|
||||
graphSegments.add(frs);
|
||||
if(positive) {
|
||||
plusAllowed = false;
|
||||
} else {
|
||||
minusAllowed = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(next == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TO-DO U-Turn
|
||||
if((next == segment || next.road.id == road.id) && next.next == null) {
|
||||
// simplification if there is no real intersection
|
||||
continue;
|
||||
}
|
||||
final RouteSegment roadNext = ctx.loadRouteSegment(x, y, ctx.config.memoryLimitation - ctx.memoryOverhead);
|
||||
if(roadNext != null &&
|
||||
!((roadNext == segment || roadNext.road.id == road.id) && roadNext.next == null)) {
|
||||
// check if there are outgoing connections in that case we need to stop processing
|
||||
boolean outgoingConnections = false;
|
||||
RouteSegment r = next;
|
||||
RouteSegment r = roadNext;
|
||||
while(r != null && !outgoingConnections) {
|
||||
if(r.road.id != road.id || r.getSegmentStart() != 0 || r.road.getOneway() != 1){
|
||||
outgoingConnections = true;
|
||||
|
@ -629,23 +538,100 @@ public class BinaryRoutePlanner {
|
|||
r = r.next;
|
||||
}
|
||||
if (outgoingConnections) {
|
||||
if (positive) {
|
||||
plusAllowed = false;
|
||||
} else {
|
||||
minusAllowed = false;
|
||||
}
|
||||
directionAllowed = false;
|
||||
}
|
||||
|
||||
|
||||
float distToFinalPoint = (float) squareRootDist(x, y, targetEndX, targetEndY);
|
||||
float distStartObstacles = segment.distanceFromStart + calculateTimeWithObstacles(ctx, road, segmentDist , obstaclesTime);
|
||||
processIntersections(ctx, graphSegments, visitedSegments,
|
||||
distStartObstacles, distToFinalPoint, segment, segmentEnd, next, reverseWaySearch, outgoingConnections);
|
||||
|
||||
distStartObstacles, distToFinalPoint, segment, segmentEnd, roadNext, reverseWaySearch, outgoingConnections);
|
||||
}
|
||||
}
|
||||
if(initDirectionAllowed && ctx.visitor != null){
|
||||
ctx.visitor.visitSegment(segment, segmentEnd, true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkIfInitialMovementAllowedOnSegment(final RoutingContext ctx, boolean reverseWaySearch,
|
||||
TLongObjectHashMap<RouteSegment> visitedSegments, RouteSegment segment, boolean direction, final RouteDataObject road
|
||||
) {
|
||||
boolean directionAllowed;
|
||||
final int middle = segment.getSegmentStart();
|
||||
int oneway = ctx.getRouter().isOneWay(road);
|
||||
// use positive direction as agreed
|
||||
if(ctx.firstRoadId == calculateRoutePointId(road, middle, true) ) {
|
||||
if(direction){
|
||||
directionAllowed = ctx.firstRoadDirection >= 0;
|
||||
} else {
|
||||
directionAllowed = ctx.firstRoadDirection <= 0;
|
||||
}
|
||||
} else if (!reverseWaySearch) {
|
||||
if(direction){
|
||||
directionAllowed = oneway >= 0;
|
||||
} else {
|
||||
directionAllowed = oneway <= 0;
|
||||
}
|
||||
} else {
|
||||
if(direction){
|
||||
directionAllowed = oneway <= 0;
|
||||
} else {
|
||||
directionAllowed = oneway >= 0;
|
||||
}
|
||||
}
|
||||
if(direction) {
|
||||
if(middle == road.getPointsLength() - 1 ||
|
||||
visitedSegments.containsKey(calculateRoutePointId(road, middle, true)) ||
|
||||
segment.getAllowedDirection() == -1) {
|
||||
directionAllowed = false;
|
||||
}
|
||||
} else {
|
||||
if(middle == 0 || visitedSegments.containsKey(calculateRoutePointId(road, middle - 1, false)) ||
|
||||
segment.getAllowedDirection() == 1) {
|
||||
directionAllowed = false;
|
||||
}
|
||||
}
|
||||
return directionAllowed;
|
||||
}
|
||||
|
||||
private boolean checkIfOppositieSegmentWasVisited(final RoutingContext ctx, boolean reverseWaySearch,
|
||||
PriorityQueue<RouteSegment> graphSegments, RouteSegment segment, TLongObjectHashMap<RouteSegment> oppositeSegments,
|
||||
final RouteDataObject road, int segmentEnd, boolean positive, int intervalId, float segmentDist, float obstaclesTime) {
|
||||
long opp = calculateRoutePointId(road, intervalId, !positive);
|
||||
if (oppositeSegments.containsKey(opp)) {
|
||||
RouteSegment opposite = oppositeSegments.get(opp);
|
||||
if (opposite.getSegmentStart() == segmentEnd) {
|
||||
FinalRouteSegment frs = new FinalRouteSegment(road, segment.getSegmentStart());
|
||||
float distStartObstacles = segment.distanceFromStart + calculateTimeWithObstacles(ctx, road, segmentDist , obstaclesTime);
|
||||
frs.setParentRoute(segment.getParentRoute());
|
||||
frs.setParentSegmentEnd(segment.getParentSegmentEnd());
|
||||
frs.reverseWaySearch = reverseWaySearch;
|
||||
frs.distanceFromStart = opposite.distanceFromStart + distStartObstacles;
|
||||
frs.distanceToEnd = 0;
|
||||
frs.opposite = opposite;
|
||||
graphSegments.add(frs);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private float calculateTimeWithObstacles(RoutingContext ctx, RouteDataObject road, float distOnRoadToPass, float obstaclesTime) {
|
||||
float priority = ctx.getRouter().defineSpeedPriority(road);
|
||||
float speed = (ctx.getRouter().defineSpeed(road) * priority);
|
||||
if (speed == 0) {
|
||||
speed = (ctx.getRouter().getMinDefaultSpeed() * priority);
|
||||
}
|
||||
// speed can not exceed max default speed according to A*
|
||||
if(speed > ctx.getRouter().getMaxDefaultSpeed()) {
|
||||
speed = ctx.getRouter().getMaxDefaultSpeed();
|
||||
}
|
||||
float distStartObstacles = obstaclesTime +
|
||||
distOnRoadToPass / speed;
|
||||
return distStartObstacles;
|
||||
|
||||
}
|
||||
|
||||
private long calculateRoutePointId(final RouteDataObject road, int intervalId, boolean positive) {
|
||||
return (road.getId() << ROUTE_POINTS) + (intervalId << 1) + (positive ? 1 : 0);
|
||||
}
|
||||
|
@ -738,6 +724,9 @@ public class BinaryRoutePlanner {
|
|||
Iterator<RouteSegment> nextIterator = null;
|
||||
if (thereAreRestrictions) {
|
||||
nextIterator = ctx.segmentsToVisitPrescripted.iterator();
|
||||
if(TRACE_ROUTING){
|
||||
System.out.println(" >> There are restrictions");
|
||||
}
|
||||
}
|
||||
// Calculate possible ways to put into priority queue
|
||||
RouteSegment next = inputNext;
|
||||
|
@ -774,13 +763,18 @@ public class BinaryRoutePlanner {
|
|||
if(sameRoadFutureDirection) {
|
||||
next.setAllowedDirection((byte) (segment.getSegmentStart() < next.getSegmentStart() ? 1 : - 1));
|
||||
}
|
||||
if(TRACE_ROUTING) {
|
||||
System.out.print(" >>");
|
||||
printRoad(next);
|
||||
}
|
||||
// put additional information to recover whole route after
|
||||
next.setParentRoute(segment);
|
||||
next.setParentSegmentEnd(segmentEnd);
|
||||
|
||||
graphSegments.add(next);
|
||||
}
|
||||
if (ctx.visitor != null) {
|
||||
ctx.visitor.visitSegment(next, false);
|
||||
// ctx.visitor.visitSegment(next, false);
|
||||
}
|
||||
} else if(!sameRoadFutureDirection){
|
||||
// the segment was already visited! We need to follow better route if it exists
|
||||
|
@ -797,7 +791,7 @@ public class BinaryRoutePlanner {
|
|||
next.setParentRoute(segment);
|
||||
next.setParentSegmentEnd(segmentEnd);
|
||||
if (ctx.visitor != null) {
|
||||
ctx.visitor.visitSegment(next, false);
|
||||
// ctx.visitor.visitSegment(next, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1295,7 +1289,7 @@ public class BinaryRoutePlanner {
|
|||
|
||||
public interface RouteSegmentVisitor {
|
||||
|
||||
public void visitSegment(RouteSegment segment, boolean poll);
|
||||
public void visitSegment(RouteSegment segment, int segmentEnd, boolean poll);
|
||||
}
|
||||
|
||||
public static class RouteSegment {
|
||||
|
|
|
@ -18,7 +18,7 @@ import org.xml.sax.helpers.DefaultHandler;
|
|||
public class RoutingConfiguration {
|
||||
// 1. parameters of routing and different tweaks
|
||||
// Influence on A* : f(x) + heuristicCoefficient*g(X)
|
||||
public double heuristicCoefficient = 1;
|
||||
public float heuristicCoefficient = 1;
|
||||
|
||||
public static final int DEFAULT_MEMORY_LIMIT = 30;
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class RoutingConfiguration {
|
|||
// 1.3 Relaxing strategy
|
||||
public boolean useRelaxingStrategy = true;
|
||||
public int ITERATIONS_TO_RELAX_NODES = 100;
|
||||
public double RELAX_NODES_IF_START_DIST_COEF = 3;
|
||||
public float RELAX_NODES_IF_START_DIST_COEF = 3;
|
||||
|
||||
// 1.4 Build A* graph in backward/forward direction (can affect results)
|
||||
// 0 - 2 ways, 1 - direct way, -1 - reverse way
|
||||
|
@ -63,7 +63,7 @@ public class RoutingConfiguration {
|
|||
}
|
||||
RoutingConfiguration i = new RoutingConfiguration();
|
||||
i.initialDirection = direction;
|
||||
i.heuristicCoefficient = parseSilentDouble(getAttribute(router, "heuristicCoefficient"), i.heuristicCoefficient);
|
||||
i.heuristicCoefficient = parseSilentFloat(getAttribute(router, "heuristicCoefficient"), i.heuristicCoefficient);
|
||||
i.ZOOM_TO_LOAD_TILES = parseSilentInt(getAttribute(router, "zoomToLoadTiles"), i.ZOOM_TO_LOAD_TILES);
|
||||
int desirable = parseSilentInt(getAttribute(router, "memoryLimitInMB"), 0);
|
||||
if(desirable != 0) {
|
||||
|
@ -78,7 +78,7 @@ public class RoutingConfiguration {
|
|||
i.useRelaxingStrategy = parseSilentBoolean(getAttribute(router, "useRelaxingStrategy"), i.useRelaxingStrategy);
|
||||
i.dynamicRoadPriorityDistance = parseSilentInt(getAttribute(router, "dynamicRoadPriorityDistance"), i.dynamicRoadPriorityDistance);
|
||||
i.ITERATIONS_TO_RELAX_NODES = parseSilentInt(getAttribute(router, "iterationsToRelaxRoutes"), i.ITERATIONS_TO_RELAX_NODES);
|
||||
i.RELAX_NODES_IF_START_DIST_COEF = parseSilentDouble(getAttribute(router, "relaxNodesIfStartDistSmallCoeff"), i.RELAX_NODES_IF_START_DIST_COEF);
|
||||
i.RELAX_NODES_IF_START_DIST_COEF = parseSilentFloat(getAttribute(router, "relaxNodesIfStartDistSmallCoeff"), i.RELAX_NODES_IF_START_DIST_COEF);
|
||||
i.planRoadDirection = parseSilentInt(getAttribute(router, "planRoadDirection"), i.planRoadDirection);
|
||||
|
||||
if (!routers.containsKey(router)) {
|
||||
|
@ -117,11 +117,11 @@ public class RoutingConfiguration {
|
|||
return Boolean.parseBoolean(t);
|
||||
}
|
||||
|
||||
private static double parseSilentDouble(String t, double v) {
|
||||
private static float parseSilentFloat(String t, float v) {
|
||||
if (t == null || t.length() == 0) {
|
||||
return v;
|
||||
}
|
||||
return Double.parseDouble(t);
|
||||
return Float.parseFloat(t);
|
||||
}
|
||||
|
||||
|
||||
|
@ -173,22 +173,22 @@ public class RoutingConfiguration {
|
|||
if (previousKey != null) {
|
||||
String k = in + ":" + previousKey;
|
||||
if (attributes.getValue("penalty") != null) {
|
||||
double penalty = parseSilentDouble(attributes.getValue("penalty"), 0);
|
||||
float penalty = parseSilentFloat(attributes.getValue("penalty"), 0);
|
||||
currentRouter.obstacles.put(k, penalty);
|
||||
double routingPenalty = parseSilentDouble(attributes.getValue("routingPenalty"), penalty );
|
||||
float routingPenalty = parseSilentFloat(attributes.getValue("routingPenalty"), penalty );
|
||||
currentRouter.routingObstacles.put(k, routingPenalty);
|
||||
}
|
||||
if (attributes.getValue("priority") != null) {
|
||||
currentRouter.highwayPriorities.put(k, parseSilentDouble(attributes.getValue("priority"), 0));
|
||||
currentRouter.highwayPriorities.put(k, parseSilentFloat(attributes.getValue("priority"), 0));
|
||||
}
|
||||
if (attributes.getValue("dynamicPriority") != null) {
|
||||
currentRouter.highwayFuturePriorities.put(k, parseSilentDouble(attributes.getValue("dynamicPriority"), 0));
|
||||
currentRouter.highwayFuturePriorities.put(k, parseSilentFloat(attributes.getValue("dynamicPriority"), 0));
|
||||
}
|
||||
if (attributes.getValue("speed") != null) {
|
||||
currentRouter.highwaySpeed.put(k, parseSilentDouble(attributes.getValue("speed"), 0));
|
||||
currentRouter.highwaySpeed.put(k, parseSilentFloat(attributes.getValue("speed"), 0));
|
||||
}
|
||||
if ("avoid".equals(previousTag)) {
|
||||
double priority = parseSilentDouble(attributes.getValue("decreasedPriority"), 0);
|
||||
float priority = parseSilentFloat(attributes.getValue("decreasedPriority"), 0);
|
||||
if (priority == 0) {
|
||||
currentRouter.avoid.put(k, priority);
|
||||
} else {
|
||||
|
@ -200,23 +200,23 @@ public class RoutingConfiguration {
|
|||
} else if("road".equals(name)) {
|
||||
previousTag = name;
|
||||
previousKey = attributes.getValue("tag") +"$" + attributes.getValue("value");
|
||||
currentRouter.highwayPriorities.put(previousKey, parseSilentDouble(attributes.getValue("priority"),
|
||||
currentRouter.highwayPriorities.put(previousKey, parseSilentFloat(attributes.getValue("priority"),
|
||||
1));
|
||||
currentRouter.highwayFuturePriorities.put(previousKey, parseSilentDouble(attributes.getValue("dynamicPriority"),
|
||||
currentRouter.highwayFuturePriorities.put(previousKey, parseSilentFloat(attributes.getValue("dynamicPriority"),
|
||||
1));
|
||||
currentRouter.highwaySpeed.put(previousKey, parseSilentDouble(attributes.getValue("speed"),
|
||||
currentRouter.highwaySpeed.put(previousKey, parseSilentFloat(attributes.getValue("speed"),
|
||||
10));
|
||||
} else if("obstacle".equals(name)) {
|
||||
previousTag = name;
|
||||
previousKey = attributes.getValue("tag") + "$" + attributes.getValue("value");
|
||||
double penalty = parseSilentDouble(attributes.getValue("penalty"), 0);
|
||||
float penalty = parseSilentFloat(attributes.getValue("penalty"), 0);
|
||||
currentRouter.obstacles.put(previousKey, penalty);
|
||||
double routingPenalty = parseSilentDouble(attributes.getValue("routingPenalty"), penalty );
|
||||
float routingPenalty = parseSilentFloat(attributes.getValue("routingPenalty"), penalty );
|
||||
currentRouter.routingObstacles.put(previousKey, routingPenalty);
|
||||
} else if("avoid".equals(name)) {
|
||||
previousTag = name;
|
||||
previousKey = attributes.getValue("tag") + "$" + attributes.getValue("value");
|
||||
double priority = parseSilentDouble(attributes.getValue("decreasedPriority"),
|
||||
float priority = parseSilentFloat(attributes.getValue("decreasedPriority"),
|
||||
0);
|
||||
if(priority == 0) {
|
||||
currentRouter.avoid.put(previousKey, priority);
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.apache.commons.logging.Log;
|
|||
public class RoutingContext {
|
||||
|
||||
public static final boolean SHOW_GC_SIZE = false;
|
||||
public boolean USE_BASEMAP = false;
|
||||
|
||||
|
||||
private final static Log log = LogUtil.getLog(RoutingContext.class);
|
||||
public static final int OPTION_NO_LOAD = 0;
|
||||
|
@ -42,6 +42,7 @@ public class RoutingContext {
|
|||
public static final int OPTION_IN_MEMORY_LOAD = 2;
|
||||
// Final context variables
|
||||
public final RoutingConfiguration config;
|
||||
private final boolean useBaseMap;
|
||||
public final NativeLibrary nativeLib;
|
||||
public final Map<BinaryMapIndexReader, List<RouteSubregion>> map = new LinkedHashMap<BinaryMapIndexReader, List<RouteSubregion>>();
|
||||
public final Map<RouteRegion, BinaryMapIndexReader> reverseMap = new LinkedHashMap<RouteRegion, BinaryMapIndexReader>();
|
||||
|
@ -96,6 +97,7 @@ public class RoutingContext {
|
|||
public RoutingContext(RoutingContext cp) {
|
||||
this.config = cp.config;
|
||||
this.map.putAll(cp.map);
|
||||
this.useBaseMap = cp.useBaseMap;
|
||||
this.reverseMap.putAll(cp.reverseMap);
|
||||
this.nativeLib = cp.nativeLib;
|
||||
// copy local data and clear caches
|
||||
|
@ -117,11 +119,16 @@ public class RoutingContext {
|
|||
}
|
||||
|
||||
public RoutingContext(RoutingConfiguration config, NativeLibrary nativeLibrary, BinaryMapIndexReader[] map) {
|
||||
this(config, nativeLibrary, map, false);
|
||||
}
|
||||
|
||||
public RoutingContext(RoutingConfiguration config, NativeLibrary nativeLibrary, BinaryMapIndexReader[] map, boolean useBasemap) {
|
||||
this.useBaseMap = useBasemap;
|
||||
for (BinaryMapIndexReader mr : map) {
|
||||
List<RouteRegion> rr = mr.getRoutingIndexes();
|
||||
List<RouteSubregion> subregions = new ArrayList<BinaryMapRouteReaderAdapter.RouteSubregion>();
|
||||
for (RouteRegion r : rr) {
|
||||
List<RouteSubregion> subregs = USE_BASEMAP ? r.getBaseSubregions() :
|
||||
List<RouteSubregion> subregs = useBaseMap ? r.getBaseSubregions() :
|
||||
r.getSubregions();
|
||||
for (RouteSubregion rs : subregs) {
|
||||
subregions.add(new RouteSubregion(rs));
|
||||
|
@ -193,7 +200,7 @@ public class RoutingContext {
|
|||
config.router = router;
|
||||
}
|
||||
|
||||
public void setHeuristicCoefficient(double heuristicCoefficient) {
|
||||
public void setHeuristicCoefficient(float heuristicCoefficient) {
|
||||
config.heuristicCoefficient = heuristicCoefficient;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<attribute name="zoomToLoadTiles" value="16" />
|
||||
<!-- by default it is 30. Value specified here overwrites all others
|
||||
(don't specify here ! it is device dependent) -->
|
||||
<attribute name="memoryLimitInMB" value="" />
|
||||
<attribute name="memoryLimitInMB" value="450" />
|
||||
|
||||
<!-- 1.2 Dynamic road prioritizing (heuristic) -->
|
||||
<attribute name="useDynamicRoadPrioritising" value="false" />
|
||||
|
|
|
@ -138,8 +138,9 @@ public class MapClusterLayer implements MapPanelLayer {
|
|||
|
||||
ctx.setVisitor(new RouteSegmentVisitor() {
|
||||
private List<RouteSegment> cache = new ArrayList<RouteSegment>();
|
||||
|
||||
@Override
|
||||
public void visitSegment(RouteSegment s, boolean poll) {
|
||||
public void visitSegment(RouteSegment s, int endSegment, boolean poll) {
|
||||
if(!ANIMATE_CLUSTERING){
|
||||
return;
|
||||
}
|
||||
|
@ -269,7 +270,7 @@ public class MapClusterLayer implements MapPanelLayer {
|
|||
if (!onTheMap.contains(toAdd.getRoad().getId())) {
|
||||
onTheMap.add(toAdd.getRoad().getId());
|
||||
// Visualization of steps !
|
||||
ctx.getVisitor().visitSegment(toAdd, true);
|
||||
ctx.getVisitor().visitSegment(toAdd, -1, true);
|
||||
}
|
||||
List<RouteSegment> nextSegments = new ArrayList<BinaryRoutePlanner.RouteSegment>();
|
||||
boolean out = false;
|
||||
|
|
|
@ -617,8 +617,7 @@ public class MapRouterLayer implements MapPanelLayer {
|
|||
RoutingConfiguration config = builder.build(props[0], RoutingConfiguration.DEFAULT_MEMORY_LIMIT / 2, props);
|
||||
// config.NUMBER_OF_DESIRABLE_TILES_IN_MEMORY = 300;
|
||||
// config.ZOOM_TO_LOAD_TILES = 14;
|
||||
RoutingContext ctx = new RoutingContext(config, NativeSwingRendering.getDefaultFromSettings(), rs);
|
||||
ctx.USE_BASEMAP = useBasemap;
|
||||
RoutingContext ctx = new RoutingContext(config, NativeSwingRendering.getDefaultFromSettings(), rs, useBasemap);
|
||||
ctx.previouslyCalculatedRoute = previousRoute;
|
||||
log.info("Use " + config.routerName + "mode for routing");
|
||||
|
||||
|
@ -655,9 +654,10 @@ public class MapRouterLayer implements MapPanelLayer {
|
|||
|
||||
private List<RouteSegment> cache = new ArrayList<RouteSegment>();
|
||||
private List<RouteSegment> pollCache = new ArrayList<RouteSegment>();
|
||||
private List<Integer> cacheInt = new ArrayList<Integer>();
|
||||
|
||||
@Override
|
||||
public void visitSegment(RouteSegment s, boolean poll) {
|
||||
public void visitSegment(RouteSegment s, int endSegment, boolean poll) {
|
||||
if(stop) {
|
||||
throw new RuntimeException("Interrupted");
|
||||
}
|
||||
|
@ -670,32 +670,44 @@ public class MapRouterLayer implements MapPanelLayer {
|
|||
}
|
||||
|
||||
cache.add(s);
|
||||
cacheInt.add(endSegment);
|
||||
if (cache.size() < steps) {
|
||||
return;
|
||||
}
|
||||
if(pause) {
|
||||
registerObjects(points, poll, pollCache);
|
||||
registerObjects(points, poll, pollCache, null);
|
||||
pollCache.clear();
|
||||
}
|
||||
registerObjects(points, !poll, cache);
|
||||
registerObjects(points, !poll, cache, cacheInt);
|
||||
cache.clear();
|
||||
cacheInt.clear();
|
||||
redraw();
|
||||
if (pause) {
|
||||
waitNextPress();
|
||||
}
|
||||
}
|
||||
|
||||
private void registerObjects(final DataTileManager<Entity> points, boolean white,
|
||||
List<RouteSegment> registerCache) {
|
||||
for (RouteSegment segment : registerCache) {
|
||||
private void registerObjects(final DataTileManager<Entity> points, boolean white, List<RouteSegment> registerCache,
|
||||
List<Integer> cacheInt) {
|
||||
for (int l = 0; l < registerCache.size(); l++) {
|
||||
RouteSegment segment = registerCache.get(l);
|
||||
Way way = new Way(-1);
|
||||
way.putTag(OSMTagKey.NAME.getValue(), segment.getTestName());
|
||||
if(white) {
|
||||
if (white) {
|
||||
way.putTag("color", "white");
|
||||
}
|
||||
for (int i = 0; i < segment.getRoad().getPointsLength(); i++) {
|
||||
net.osmand.osm.Node n = createNode(segment, i);
|
||||
way.addNode(n);
|
||||
int from = cacheInt != null ? segment.getSegmentStart() : segment.getSegmentStart() - 2;
|
||||
int to = cacheInt != null ? cacheInt.get(l) : segment.getSegmentStart() + 2;
|
||||
if(from > to) {
|
||||
int x = from;
|
||||
from = to;
|
||||
to = x;
|
||||
}
|
||||
for (int i = from; i <= to; i++) {
|
||||
if (i >= 0 && i < segment.getRoad().getPointsLength()) {
|
||||
net.osmand.osm.Node n = createNode(segment, i);
|
||||
way.addNode(n);
|
||||
}
|
||||
}
|
||||
LatLon n = way.getLatLon();
|
||||
points.registerObject(n.getLatitude(), n.getLongitude(), way);
|
||||
|
|
Loading…
Reference in a new issue