More precise routing

This commit is contained in:
Victor Shcherb 2012-10-09 19:36:23 +02:00
parent e068d17178
commit 3c113e7bf7
4 changed files with 205 additions and 132 deletions

View file

@ -23,8 +23,8 @@ public class BinaryRoutePlanner {
public static boolean PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true; public static boolean PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true;
private final int REVERSE_WAY_RESTRICTION_ONLY = 1024; private final int REVERSE_WAY_RESTRICTION_ONLY = 1024;
private final int STANDARD_ROAD_IN_QUEUE_OVERHEAD = 750; /*private*/ final int STANDARD_ROAD_IN_QUEUE_OVERHEAD = 220;
private final int STANDARD_ROAD_VISITED_OVERHEAD = 250; /*private */final int STANDARD_ROAD_VISITED_OVERHEAD = 150;
protected static final Log log = LogUtil.getLog(BinaryRoutePlanner.class); protected static final Log log = LogUtil.getLog(BinaryRoutePlanner.class);
@ -225,11 +225,12 @@ public class BinaryRoutePlanner {
// measure time // measure time
ctx.timeToLoad = 0; ctx.timeToLoad = 0;
ctx.visitedSegments = 0; ctx.visitedSegments = 0;
ctx.memoryOverhead = 1000;
ctx.timeToCalculate = System.nanoTime(); ctx.timeToCalculate = System.nanoTime();
if(ctx.config.initialDirection != null) { if(ctx.config.initialDirection != null) {
// mark here as positive for further check // mark here as positive for further check
ctx.firstRoadId = calculateRoutePointId(start.getRoad(), start.getSegmentStart(), true); ctx.firstRoadId = calculateRoutePointId(start.getRoad(), start.getSegmentStart(), true);
double plusDir = start.getRoad().directionRoute(start.segmentStart, true); double plusDir = start.getRoad().directionRoute(start.getSegmentStart(), true);
double diff = plusDir - ctx.config.initialDirection; double diff = plusDir - ctx.config.initialDirection;
if(Math.abs(MapUtils.alignAngleDifference(diff)) <= Math.PI / 3) { if(Math.abs(MapUtils.alignAngleDifference(diff)) <= Math.PI / 3) {
ctx.firstRoadDirection = 1; ctx.firstRoadDirection = 1;
@ -279,8 +280,8 @@ public class BinaryRoutePlanner {
for (RouteSegmentResult rr : rlist) { for (RouteSegmentResult rr : rlist) {
RouteSegment segment = new RouteSegment(rr.getObject(), rr.getEndPointIndex()); RouteSegment segment = new RouteSegment(rr.getObject(), rr.getEndPointIndex());
if (previous != null) { if (previous != null) {
previous.parentRoute = segment; previous.setParentRoute(segment);
previous.parentSegmentEnd = rr.getStartPointIndex(); previous.setParentSegmentEnd(rr.getStartPointIndex());
boolean positive = rr.getStartPointIndex() < rr.getEndPointIndex(); boolean positive = rr.getStartPointIndex() < rr.getEndPointIndex();
long t = calculateRoutePointId(rr.getObject(), positive ? rr.getEndPointIndex() - 1 : rr.getEndPointIndex(), long t = calculateRoutePointId(rr.getObject(), positive ? rr.getEndPointIndex() - 1 : rr.getEndPointIndex(),
positive); positive);
@ -293,10 +294,10 @@ public class BinaryRoutePlanner {
} }
// for start : f(start) = g(start) + h(start) = 0 + h(start) = h(start) // for start : f(start) = g(start) + h(start) = 0 + h(start) = h(start)
int targetEndX = end.road.getPoint31XTile(end.segmentStart); int targetEndX = end.road.getPoint31XTile(end.getSegmentStart());
int targetEndY = end.road.getPoint31YTile(end.segmentStart); int targetEndY = end.road.getPoint31YTile(end.getSegmentStart());
int startX = start.road.getPoint31XTile(start.segmentStart); int startX = start.road.getPoint31XTile(start.getSegmentStart());
int startY = start.road.getPoint31YTile(start.segmentStart); int startY = start.road.getPoint31YTile(start.getSegmentStart());
float estimatedDistance = (float) h(ctx, targetEndX, targetEndY, startX, startY); float estimatedDistance = (float) h(ctx, targetEndX, targetEndY, startX, startY);
end.distanceToEnd = start.distanceToEnd = estimatedDistance; end.distanceToEnd = start.distanceToEnd = estimatedDistance;
@ -316,24 +317,27 @@ public class BinaryRoutePlanner {
FinalRouteSegment finalSegment = null; FinalRouteSegment finalSegment = null;
while (!graphSegments.isEmpty()) { while (!graphSegments.isEmpty()) {
RouteSegment segment = graphSegments.poll(); RouteSegment segment = graphSegments.poll();
int memOverhead = (visitedDirectSegments.size() + visitedOppositeSegments.size()) * STANDARD_ROAD_VISITED_OVERHEAD + // use accumulative approach
ctx.memoryOverhead = (visitedDirectSegments.size() + visitedOppositeSegments.size()) * STANDARD_ROAD_VISITED_OVERHEAD +
(graphDirectSegments.size() + (graphDirectSegments.size() +
graphReverseSegments.size()) * STANDARD_ROAD_IN_QUEUE_OVERHEAD; graphReverseSegments.size()) * STANDARD_ROAD_IN_QUEUE_OVERHEAD;
// String pr = " pend="+segment.parentSegmentEnd +" " +( segment.parentRoute == null ? "" : (" parent=" + segment.parentRoute.road)); // String pr = " pend="+segment.parentSegmentEnd +" " +( segment.parentRoute == null ? "" : (" parent=" + segment.parentRoute.road));
// System.out.println("Seg " + segment.road + " ind=" + segment.segmentStart + // System.out.println("Seg " + segment.road + " ind=" + segment.segmentStart +
// " ds=" + ((float)segment.distanceFromStart) + " es="+((float)segment.distanceToEnd) + pr); // " ds=" + ((float)segment.distanceFromStart) + " es="+((float)segment.distanceToEnd) + pr);
if(segment instanceof FinalRouteSegment) { if(segment instanceof FinalRouteSegment) {
if(RoutingContext.SHOW_GC_SIZE){ if(RoutingContext.SHOW_GC_SIZE){
log.warn("Estimated overhead " + (memOverhead / (1<<20))+ " mb"); log.warn("Estimated overhead " + (ctx.memoryOverhead / (1<<20))+ " mb");
printMemoryConsumption("Memory occupied after calculation : "); printMemoryConsumption("Memory occupied after calculation : ");
} }
finalSegment = (FinalRouteSegment) segment; finalSegment = (FinalRouteSegment) segment;
break; break;
} }
if (memOverhead > ctx.config.memoryLimitation * 0.95 && RoutingContext.SHOW_GC_SIZE) { if (ctx.memoryOverhead > ctx.config.memoryLimitation * 0.95 && RoutingContext.SHOW_GC_SIZE) {
printMemoryConsumption("Memory occupied before exception : "); printMemoryConsumption("Memory occupied before exception : ");
} }
if(memOverhead > ctx.config.memoryLimitation * 0.95) { if(ctx.memoryOverhead > ctx.config.memoryLimitation * 0.95) {
throw new IllegalStateException("There is no enough memory " + ctx.config.memoryLimitation/(1<<20) + " Mb"); throw new IllegalStateException("There is no enough memory " + ctx.config.memoryLimitation/(1<<20) + " Mb");
} }
ctx.visitedSegments++; ctx.visitedSegments++;
@ -343,10 +347,10 @@ public class BinaryRoutePlanner {
} }
if (!inverse) { if (!inverse) {
processRouteSegment(ctx, false, graphDirectSegments, visitedDirectSegments, targetEndX, targetEndY, processRouteSegment(ctx, false, graphDirectSegments, visitedDirectSegments, targetEndX, targetEndY,
segment, visitedOppositeSegments, memOverhead); segment, visitedOppositeSegments);
} else { } else {
processRouteSegment(ctx, true, graphReverseSegments, visitedOppositeSegments, startX, startY, segment, processRouteSegment(ctx, true, graphReverseSegments, visitedOppositeSegments, startX, startY, segment,
visitedDirectSegments, memOverhead); visitedDirectSegments);
} }
if(graphReverseSegments.isEmpty()){ if(graphReverseSegments.isEmpty()){
throw new IllegalArgumentException("Route is not found to selected target point."); throw new IllegalArgumentException("Route is not found to selected target point.");
@ -423,13 +427,13 @@ public class BinaryRoutePlanner {
// println("Relaxing : before " + before + " after " + after + " minend " + ((float) mine)); // println("Relaxing : before " + before + " after " + after + " minend " + ((float) mine));
} }
private double h(final RoutingContext ctx, int targetEndX, int targetEndY, private float h(final RoutingContext ctx, int targetEndX, int targetEndY,
int startX, int startY) { int startX, int startY) {
double distance = squareRootDist(startX, startY, targetEndX, targetEndY); double distance = squareRootDist(startX, startY, targetEndX, targetEndY);
return distance / ctx.getRouter().getMaxDefaultSpeed(); return (float) (distance / ctx.getRouter().getMaxDefaultSpeed());
} }
protected static double h(RoutingContext ctx, double distToFinalPoint, RouteSegment next) { protected static float h(RoutingContext ctx, float distToFinalPoint, RouteSegment next) {
double result = distToFinalPoint / ctx.getRouter().getMaxDefaultSpeed(); double result = distToFinalPoint / ctx.getRouter().getMaxDefaultSpeed();
if(ctx.isUseDynamicRoadPrioritising() && next != null){ if(ctx.isUseDynamicRoadPrioritising() && next != null){
double priority = ctx.getRouter().getFutureRoadPriority(next.road); double priority = ctx.getRouter().getFutureRoadPriority(next.road);
@ -441,7 +445,7 @@ public class BinaryRoutePlanner {
dist / (ctx.getRouter().getMaxDefaultSpeed() * priority); dist / (ctx.getRouter().getMaxDefaultSpeed() * priority);
} }
} }
return result; return (float) result;
} }
@ -476,14 +480,14 @@ public class BinaryRoutePlanner {
private void processRouteSegment(final RoutingContext ctx, boolean reverseWaySearch, private void processRouteSegment(final RoutingContext ctx, boolean reverseWaySearch,
PriorityQueue<RouteSegment> graphSegments, TLongObjectHashMap<RouteSegment> visitedSegments, int targetEndX, int targetEndY, PriorityQueue<RouteSegment> graphSegments, TLongObjectHashMap<RouteSegment> visitedSegments, int targetEndX, int targetEndY,
RouteSegment segment, TLongObjectHashMap<RouteSegment> oppositeSegments, int memOverhead) throws IOException { RouteSegment segment, TLongObjectHashMap<RouteSegment> oppositeSegments) throws IOException {
// Always start from segmentStart (!), not from segmentEnd // Always start from segmentStart (!), not from segmentEnd
// It makes difference only for the first start segment // It makes difference only for the first start segment
// Middle point will always be skipped from observation considering already visited // Middle point will always be skipped from observation considering already visited
final RouteDataObject road = segment.road; final RouteDataObject road = segment.road;
final int middle = segment.segmentStart; final int middle = segment.getSegmentStart();
double obstaclePlusTime = 0; float obstaclePlusTime = 0;
double obstacleMinusTime = 0; float obstacleMinusTime = 0;
int oneway = ctx.getRouter().isOneWay(road); int oneway = ctx.getRouter().isOneWay(road);
@ -501,29 +505,31 @@ public class BinaryRoutePlanner {
plusAllowed = oneway <= 0; plusAllowed = oneway <= 0;
} }
if(middle == road.getPointsLength() - 1 || if(middle == road.getPointsLength() - 1 ||
visitedSegments.containsKey(calculateRoutePointId(road, middle, true))) { visitedSegments.containsKey(calculateRoutePointId(road, middle, true)) ||
segment.getAllowedDirection() == -1) {
plusAllowed = false; plusAllowed = false;
} }
if(middle == 0 || visitedSegments.containsKey(calculateRoutePointId(road, middle - 1, false))) { if(middle == 0 || visitedSegments.containsKey(calculateRoutePointId(road, middle - 1, false)) ||
segment.getAllowedDirection() == 1) {
minusAllowed = false; minusAllowed = false;
} }
// +/- diff from middle point // +/- diff from middle point
int d = plusAllowed ? 1 : -1; int d = plusAllowed ? 1 : -1;
if(segment.parentRoute != null) { if(segment.getParentRoute() != null) {
if(plusAllowed && middle < segment.getRoad().getPointsLength() - 1) { if(plusAllowed && middle < segment.getRoad().getPointsLength() - 1) {
obstaclePlusTime = ctx.getRouter().calculateTurnTime(segment, segment.getRoad().getPointsLength() - 1, obstaclePlusTime = (float) ctx.getRouter().calculateTurnTime(segment, segment.getRoad().getPointsLength() - 1,
segment.parentRoute, segment.parentSegmentEnd); segment.getParentRoute(), segment.getParentSegmentEnd());
} }
if(minusAllowed && middle > 0) { if(minusAllowed && middle > 0) {
obstacleMinusTime = ctx.getRouter().calculateTurnTime(segment, 0, obstacleMinusTime = (float) ctx.getRouter().calculateTurnTime(segment, 0,
segment.parentRoute, segment.parentSegmentEnd); segment.getParentRoute(), segment.getParentSegmentEnd());
} }
} }
// Go through all point of the way and find ways to continue // 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) // ! Actually there is small bug when there is restriction to move forward on the way (it doesn't take into account)
double posSegmentDist = 0; float posSegmentDist = 0;
double negSegmentDist = 0; float negSegmentDist = 0;
while (minusAllowed || plusAllowed) { while (minusAllowed || plusAllowed) {
// 1. calculate point not equal to middle // 1. calculate point not equal to middle
// (algorithm should visit all point on way if it is not oneway) // (algorithm should visit all point on way if it is not oneway)
@ -557,7 +563,7 @@ public class BinaryRoutePlanner {
long opp = calculateRoutePointId(road, intervalId, !positive); long opp = calculateRoutePointId(road, intervalId, !positive);
if (oppositeSegments.containsKey(opp)) { if (oppositeSegments.containsKey(opp)) {
opposite = oppositeSegments.get(opp); opposite = oppositeSegments.get(opp);
if (opposite.segmentStart != segmentEnd) { if (opposite.getSegmentStart() != segmentEnd) {
opposite = null; opposite = null;
} }
} }
@ -593,27 +599,26 @@ public class BinaryRoutePlanner {
// could be expensive calculation // could be expensive calculation
RouteSegment next = ctx.loadRouteSegment(x, y, ctx.config.memoryLimitation - memOverhead); RouteSegment next = ctx.loadRouteSegment(x, y, ctx.config.memoryLimitation - ctx.memoryOverhead);
// 3. get intersected ways // 3. get intersected ways
if (next != null || opposite != null) { if (next != null || opposite != null) {
// Using A* routing algorithm // Using A* routing algorithm
// g(x) - calculate distance to that point and calculate time // g(x) - calculate distance to that point and calculate time
double priority = ctx.getRouter().defineSpeedPriority(road); float priority = (float) ctx.getRouter().defineSpeedPriority(road);
double speed = ctx.getRouter().defineSpeed(road) * priority; float speed = (float) (ctx.getRouter().defineSpeed(road) * priority);
if (speed == 0) { if (speed == 0) {
speed = ctx.getRouter().getMinDefaultSpeed() * priority; speed = (float) (ctx.getRouter().getMinDefaultSpeed() * priority);
} }
double distOnRoadToPass = positive? posSegmentDist : negSegmentDist; float distOnRoadToPass = positive? posSegmentDist : negSegmentDist;
double distStartObstacles = segment.distanceFromStart + ( positive ? obstaclePlusTime : obstacleMinusTime) + float distStartObstacles = segment.distanceFromStart + ( positive ? obstaclePlusTime : obstacleMinusTime) +
distOnRoadToPass / speed; distOnRoadToPass / speed;
if(opposite != null) { if(opposite != null) {
FinalRouteSegment frs = new FinalRouteSegment(road, segment.segmentStart); FinalRouteSegment frs = new FinalRouteSegment(road, segment.getSegmentStart());
frs.parentRoute = segment.parentRoute; frs.setParentRoute(segment.getParentRoute());
frs.parentSegmentEnd = segment.parentSegmentEnd; frs.setParentSegmentEnd(segment.getParentSegmentEnd());
frs.reverseWaySearch = reverseWaySearch; frs.reverseWaySearch = reverseWaySearch;
frs.finalSegmentEnd = segmentEnd;
frs.distanceFromStart = opposite.distanceFromStart + distStartObstacles; frs.distanceFromStart = opposite.distanceFromStart + distStartObstacles;
frs.distanceToEnd = 0; frs.distanceToEnd = 0;
frs.opposite = opposite; frs.opposite = opposite;
@ -634,15 +639,33 @@ public class BinaryRoutePlanner {
// simplification if there is no real intersection // simplification if there is no real intersection
continue; continue;
} }
// check if there are outgoing connections in that case we need to stop processing
boolean outgoingConnections = false;
RouteSegment r = next;
while(r != null && !outgoingConnections) {
if(r.road.id != road.id || r.getSegmentStart() != 0 || r.road.getOneway() != 1){
outgoingConnections = true;
}
r = r.next;
}
if (outgoingConnections) {
if (positive) {
plusAllowed = false;
} else {
minusAllowed = false;
}
}
double distToFinalPoint = squareRootDist(x, y, targetEndX, targetEndY);
float distToFinalPoint = (float) squareRootDist(x, y, targetEndX, targetEndY);
processIntersections(ctx, graphSegments, visitedSegments, processIntersections(ctx, graphSegments, visitedSegments,
distStartObstacles, distToFinalPoint, segment, segmentEnd, next, reverseWaySearch); distStartObstacles, distToFinalPoint, segment, segmentEnd, next, reverseWaySearch, outgoingConnections);
} }
} }
} }
private long calculateRoutePointId(final RouteDataObject road, int intervalId, boolean positive) { private long calculateRoutePointId(final RouteDataObject road, int intervalId, boolean positive) {
return (road.getId() << ROUTE_POINTS) + (intervalId << 1) + (positive ? 1 : 0); return (road.getId() << ROUTE_POINTS) + (intervalId << 1) + (positive ? 1 : 0);
} }
@ -727,10 +750,11 @@ public class BinaryRoutePlanner {
private void processIntersections(RoutingContext ctx, PriorityQueue<RouteSegment> graphSegments, private void processIntersections(RoutingContext ctx, PriorityQueue<RouteSegment> graphSegments,
TLongObjectHashMap<RouteSegment> visitedSegments, double distFromStart, double distToFinalPoint, TLongObjectHashMap<RouteSegment> visitedSegments, float distFromStart, float distToFinalPoint,
RouteSegment segment, int segmentEnd, RouteSegment inputNext, boolean reverseWay) { RouteSegment segment, int segmentEnd, RouteSegment inputNext, boolean reverseWaySearch,
byte direction = reverseWay ? (byte)-1 : (byte)1; boolean addSameRoadFutureDirection) {
boolean thereAreRestrictions = proccessRestrictions(ctx, segment.road, inputNext, reverseWay); byte searchDirection = reverseWaySearch ? (byte)-1 : (byte)1;
boolean thereAreRestrictions = proccessRestrictions(ctx, segment.road, inputNext, reverseWaySearch);
Iterator<RouteSegment> nextIterator = null; Iterator<RouteSegment> nextIterator = null;
if (thereAreRestrictions) { if (thereAreRestrictions) {
nextIterator = ctx.segmentsToVisitPrescripted.iterator(); nextIterator = ctx.segmentsToVisitPrescripted.iterator();
@ -742,49 +766,56 @@ public class BinaryRoutePlanner {
if (nextIterator != null) { if (nextIterator != null) {
next = nextIterator.next(); next = nextIterator.next();
} }
boolean nextPlusNotAllowed = (next.segmentStart == next.road.getPointsLength() - 1) || boolean nextPlusNotAllowed = (next.getSegmentStart() == next.road.getPointsLength() - 1) ||
visitedSegments.containsKey(calculateRoutePointId(next.road, next.segmentStart, true)); visitedSegments.containsKey(calculateRoutePointId(next.road, next.getSegmentStart(), true));
boolean nextMinusNotAllowed = (next.segmentStart == 0) || boolean nextMinusNotAllowed = (next.getSegmentStart() == 0) ||
visitedSegments.containsKey(calculateRoutePointId(next.road, next.segmentStart - 1, false)); visitedSegments.containsKey(calculateRoutePointId(next.road, next.getSegmentStart() - 1, false));
boolean skipSameDirection = next.road.id == segment.road.id && next.segmentStart == segmentEnd; boolean sameRoadFutureDirection = next.road.id == segment.road.id && next.getSegmentStart() == segmentEnd;
// road.id could be equal on roundabout, but we should accept them // road.id could be equal on roundabout, but we should accept them
boolean alreadyVisited = nextPlusNotAllowed && nextMinusNotAllowed; boolean alreadyVisited = nextPlusNotAllowed && nextMinusNotAllowed;
if (!alreadyVisited && !skipSameDirection) { boolean skipRoad = sameRoadFutureDirection && !addSameRoadFutureDirection;
double distanceToEnd = h(ctx, distToFinalPoint, next); if (!alreadyVisited && !skipRoad) {
float distanceToEnd = h(ctx, distToFinalPoint, next);
// assigned to wrong direction // assigned to wrong direction
if(next.directionAssigned == -direction){ if(next.getDirectionAssigned() == -searchDirection){
next = new RouteSegment(next.getRoad(), next.segmentStart); next = new RouteSegment(next.getRoad(), next.getSegmentStart());
} }
if (next.parentRoute == null
if (next.getParentRoute() == null
|| ctx.roadPriorityComparator(next.distanceFromStart, next.distanceToEnd, distFromStart, distanceToEnd) > 0) { || ctx.roadPriorityComparator(next.distanceFromStart, next.distanceToEnd, distFromStart, distanceToEnd) > 0) {
if (next.parentRoute != null) { if (next.getParentRoute() != null) {
// already in queue remove it
if (!graphSegments.remove(next)) { if (!graphSegments.remove(next)) {
throw new IllegalStateException("Should handled by direction flag"); throw new IllegalStateException("Should be handled by direction flag");
} }
} }
next.directionAssigned = direction; next.assignDirection(searchDirection);
next.distanceFromStart = distFromStart; next.distanceFromStart = distFromStart;
next.distanceToEnd = distanceToEnd; next.distanceToEnd = distanceToEnd;
if(sameRoadFutureDirection) {
next.setAllowedDirection((byte) (segment.getSegmentStart() < next.getSegmentStart() ? 1 : - 1));
}
// put additional information to recover whole route after // put additional information to recover whole route after
next.parentRoute = segment; next.setParentRoute(segment);
next.parentSegmentEnd = segmentEnd; next.setParentSegmentEnd(segmentEnd);
graphSegments.add(next); graphSegments.add(next);
} }
if (ctx.visitor != null) { if (ctx.visitor != null) {
ctx.visitor.visitSegment(next, false); ctx.visitor.visitSegment(next, false);
} }
} else if(!skipSameDirection){ } else if(!sameRoadFutureDirection){
// the segment was already visited! We need to follow better route if it exists // the segment was already visited! We need to follow better route if it exists
// that is very strange situation and almost exception (it can happen when we underestimate distnceToEnd) // that is very strange situation and almost exception (it can happen when we underestimate distnceToEnd)
if (next.directionAssigned == direction && if (next.getDirectionAssigned() == searchDirection &&
distFromStart < next.distanceFromStart && next.road.id != segment.road.id) { distFromStart < next.distanceFromStart && next.road.id != segment.road.id) {
if(ctx.config.heuristicCoefficient <= 1) {
throw new IllegalStateException("distance from start " + distFromStart + " < " +next.distanceFromStart);
}
// That code is incorrect (when segment is processed itself, // That code is incorrect (when segment is processed itself,
// then it tries to make wrong u-turn) - // then it tries to make wrong u-turn) -
// this situation should be very carefully checked in future (seems to be fixed) // this situation should be very carefully checked in future (seems to be fixed)
next.distanceFromStart = distFromStart; next.distanceFromStart = distFromStart;
next.parentRoute = segment; next.setParentRoute(segment);
next.parentSegmentEnd = segmentEnd; next.setParentSegmentEnd(segmentEnd);
if (ctx.visitor != null) { if (ctx.visitor != null) {
ctx.visitor.visitSegment(next, false); ctx.visitor.visitSegment(next, false);
} }
@ -809,17 +840,18 @@ public class BinaryRoutePlanner {
List<RouteSegmentResult> result = new ArrayList<RouteSegmentResult>(); List<RouteSegmentResult> result = new ArrayList<RouteSegmentResult>();
if (finalSegment != null) { if (finalSegment != null) {
println("Routing calculated time distance " + finalSegment.distanceFromStart);
// Get results from opposite direction roads // Get results from opposite direction roads
RouteSegment segment = finalSegment.reverseWaySearch ? finalSegment : finalSegment.opposite.parentRoute; RouteSegment segment = finalSegment.reverseWaySearch ? finalSegment : finalSegment.opposite.getParentRoute();
int parentSegmentStart = finalSegment.reverseWaySearch ? finalSegment.opposite.segmentStart : finalSegment.opposite.parentSegmentEnd; int parentSegmentStart = finalSegment.reverseWaySearch ? finalSegment.opposite.getSegmentStart() : finalSegment.opposite.getParentSegmentEnd();
if(segment != null) { if(segment != null) {
// println(segment.road +" 1->"+ finalSegment.reverseWaySearch+"?"+finalSegment.finalSegmentEnd+":"+finalSegment.opposite.parentSegmentEnd + "="+ finalSegment.opposite.segmentStart); // println(segment.road +" 1->"+ finalSegment.reverseWaySearch+"?"+finalSegment.finalSegmentEnd+":"+finalSegment.opposite.parentSegmentEnd + "="+ finalSegment.opposite.segmentStart);
} }
while (segment != null) { while (segment != null) {
RouteSegmentResult res = new RouteSegmentResult(segment.road, parentSegmentStart, segment.segmentStart); RouteSegmentResult res = new RouteSegmentResult(segment.road, parentSegmentStart, segment.getSegmentStart());
parentSegmentStart = segment.parentSegmentEnd; parentSegmentStart = segment.getParentSegmentEnd();
segment = segment.parentRoute; segment = segment.getParentRoute();
if (res.getStartPointIndex() != res.getEndPointIndex()) { if (res.getStartPointIndex() != res.getEndPointIndex()) {
result.add(res); result.add(res);
} }
@ -827,16 +859,16 @@ public class BinaryRoutePlanner {
// reverse it just to attach good direction roads // reverse it just to attach good direction roads
Collections.reverse(result); Collections.reverse(result);
segment = finalSegment.reverseWaySearch ? finalSegment.opposite.parentRoute : finalSegment; segment = finalSegment.reverseWaySearch ? finalSegment.opposite.getParentRoute() : finalSegment;
int parentSegmentEnd = finalSegment.reverseWaySearch ? finalSegment.opposite.parentSegmentEnd : finalSegment.opposite.segmentStart; int parentSegmentEnd = finalSegment.reverseWaySearch ? finalSegment.opposite.getParentSegmentEnd() : finalSegment.opposite.getSegmentStart();
if(segment != null) { if(segment != null) {
// println(segment.road +" 2->"+ finalSegment.reverseWaySearch+"?"+finalSegment.finalSegmentEnd+":"+finalSegment.opposite.parentSegmentEnd + "="+ finalSegment.opposite.segmentStart); // println(segment.road +" 2->"+ finalSegment.reverseWaySearch+"?"+finalSegment.finalSegmentEnd+":"+finalSegment.opposite.parentSegmentEnd + "="+ finalSegment.opposite.segmentStart);
} }
while (segment != null) { while (segment != null) {
RouteSegmentResult res = new RouteSegmentResult(segment.road, segment.segmentStart, parentSegmentEnd); RouteSegmentResult res = new RouteSegmentResult(segment.road, segment.getSegmentStart(), parentSegmentEnd);
parentSegmentEnd = segment.parentSegmentEnd; parentSegmentEnd = segment.getParentSegmentEnd();
segment = segment.parentRoute; segment = segment.getParentRoute();
// happens in smart recalculation // happens in smart recalculation
if (res.getStartPointIndex() != res.getEndPointIndex()) { if (res.getStartPointIndex() != res.getEndPointIndex()) {
result.add(res); result.add(res);
@ -936,10 +968,10 @@ public class BinaryRoutePlanner {
} }
println("ROUTE : "); println("ROUTE : ");
double startLat = MapUtils.get31LatitudeY(start.road.getPoint31YTile(start.segmentStart)); double startLat = MapUtils.get31LatitudeY(start.road.getPoint31YTile(start.getSegmentStart()));
double startLon = MapUtils.get31LongitudeX(start.road.getPoint31XTile(start.segmentStart)); double startLon = MapUtils.get31LongitudeX(start.road.getPoint31XTile(start.getSegmentStart()));
double endLat = MapUtils.get31LatitudeY(end.road.getPoint31YTile(end.segmentStart)); double endLat = MapUtils.get31LatitudeY(end.road.getPoint31YTile(end.getSegmentStart()));
double endLon = MapUtils.get31LongitudeX(end.road.getPoint31XTile(end.segmentStart)); double endLon = MapUtils.get31LongitudeX(end.road.getPoint31XTile(end.getSegmentStart()));
StringBuilder add = new StringBuilder(); StringBuilder add = new StringBuilder();
add.append("loadedTiles = \"").append(ctx.loadedTiles).append("\" "); add.append("loadedTiles = \"").append(ctx.loadedTiles).append("\" ");
add.append("visitedSegments = \"").append(ctx.visitedSegments).append("\" "); add.append("visitedSegments = \"").append(ctx.visitedSegments).append("\" ");
@ -1249,18 +1281,18 @@ public class BinaryRoutePlanner {
// TODO restrictions can be considered as well // TODO restrictions can be considered as well
int oneWay = ctx.getRouter().isOneWay(addRoad); int oneWay = ctx.getRouter().isOneWay(addRoad);
if (oneWay >= 0 && routeSegment.segmentStart < addRoad.getPointsLength() - 1) { if (oneWay >= 0 && routeSegment.getSegmentStart() < addRoad.getPointsLength() - 1) {
long pointL = getPoint(addRoad, routeSegment.segmentStart + 1); long pointL = getPoint(addRoad, routeSegment.getSegmentStart() + 1);
if(pointL != nextL && pointL != prevL) { if(pointL != nextL && pointL != prevL) {
// if way contains same segment (nodes) as different way (do not attach it) // if way contains same segment (nodes) as different way (do not attach it)
rr.attachRoute(pointInd, new RouteSegmentResult(addRoad, routeSegment.segmentStart, addRoad.getPointsLength() - 1)); rr.attachRoute(pointInd, new RouteSegmentResult(addRoad, routeSegment.getSegmentStart(), addRoad.getPointsLength() - 1));
} }
} }
if (oneWay <= 0 && routeSegment.segmentStart > 0) { if (oneWay <= 0 && routeSegment.getSegmentStart() > 0) {
long pointL = getPoint(addRoad, routeSegment.segmentStart - 1); long pointL = getPoint(addRoad, routeSegment.getSegmentStart() - 1);
// if way contains same segment (nodes) as different way (do not attach it) // if way contains same segment (nodes) as different way (do not attach it)
if(pointL != nextL && pointL != prevL) { if(pointL != nextL && pointL != prevL) {
rr.attachRoute(pointInd, new RouteSegmentResult(addRoad, routeSegment.segmentStart, 0)); rr.attachRoute(pointInd, new RouteSegmentResult(addRoad, routeSegment.getSegmentStart(), 0));
} }
} }
} }
@ -1283,7 +1315,7 @@ public class BinaryRoutePlanner {
} }
public static class RouteSegment { public static class RouteSegment {
final int segmentStart; final short segStart;
final RouteDataObject road; final RouteDataObject road;
// needed to store intersection of routes // needed to store intersection of routes
RouteSegment next = null; RouteSegment next = null;
@ -1291,17 +1323,52 @@ public class BinaryRoutePlanner {
// search context (needed for searching route) // search context (needed for searching route)
// Initially it should be null (!) because it checks was it segment visited before // Initially it should be null (!) because it checks was it segment visited before
RouteSegment parentRoute = null; RouteSegment parentRoute = null;
int parentSegmentEnd = 0; short parentSegmentEnd = 0;
// 1 - positive , -1 - negative, 0 not assigned // 1 - positive , -1 - negative, 0 not assigned
byte directionAssigned = 0; byte directionAssgn = 0;
// 1 - only positive allowed, -1 - only negative allowed
byte allowedDirection = 0;
// distance measured in time (seconds) // distance measured in time (seconds)
double distanceFromStart = 0; float distanceFromStart = 0;
double distanceToEnd = 0; float distanceToEnd = 0;
public RouteSegment(RouteDataObject road, int segmentStart) { public RouteSegment(RouteDataObject road, int segmentStart) {
this.road = road; this.road = road;
this.segmentStart = segmentStart; this.segStart = (short) segmentStart;
}
public byte getDirectionAssigned(){
return directionAssgn;
}
public RouteSegment getParentRoute() {
return parentRoute;
}
public void setParentRoute(RouteSegment parentRoute) {
this.parentRoute = parentRoute;
}
public void assignDirection(byte b) {
directionAssgn = b;
}
public byte getAllowedDirection() {
return allowedDirection;
}
public void setAllowedDirection(byte allowedDirection) {
this.allowedDirection = allowedDirection;
}
public void setParentSegmentEnd(int parentSegmentEnd) {
this.parentSegmentEnd = (short) parentSegmentEnd;
}
public int getParentSegmentEnd() {
return parentSegmentEnd;
} }
public RouteSegment getNext() { public RouteSegment getNext() {
@ -1309,7 +1376,7 @@ public class BinaryRoutePlanner {
} }
public int getSegmentStart() { public int getSegmentStart() {
return segmentStart; return segStart;
} }
public RouteDataObject getRoad() { public RouteDataObject getRoad() {
@ -1326,7 +1393,6 @@ public class BinaryRoutePlanner {
boolean reverseWaySearch; boolean reverseWaySearch;
RouteSegment opposite; RouteSegment opposite;
int finalSegmentEnd;
public FinalRouteSegment(RouteDataObject road, int segmentStart) { public FinalRouteSegment(RouteDataObject road, int segmentStart) {
super(road, segmentStart); super(road, segmentStart);

View file

@ -286,8 +286,8 @@ public class GeneralRouter extends VehicleRouter {
return rt; return rt;
} }
if (getLeftTurn() > 0 || getRightTurn() > 0) { if (getLeftTurn() > 0 || getRightTurn() > 0) {
double a1 = segment.getRoad().directionRoute(segment.segmentStart, segment.segmentStart < segmentEnd); double a1 = segment.getRoad().directionRoute(segment.getSegmentStart(), segment.getSegmentStart() < segmentEnd);
double a2 = prev.getRoad().directionRoute(prevSegmentEnd, prevSegmentEnd < prev.segmentStart); double a2 = prev.getRoad().directionRoute(prevSegmentEnd, prevSegmentEnd < prev.getSegmentStart());
double diff = Math.abs(MapUtils.alignAngleDifference(a1 - a2 - Math.PI)); double diff = Math.abs(MapUtils.alignAngleDifference(a1 - a2 - Math.PI));
// more like UT // more like UT
if (diff > 2 * Math.PI / 3) { if (diff > 2 * Math.PI / 3) {

View file

@ -33,7 +33,7 @@ import org.apache.commons.logging.Log;
public class RoutingContext { public class RoutingContext {
public static final boolean SHOW_GC_SIZE = false; public static final boolean SHOW_GC_SIZE = true;
private final static Log log = LogUtil.getLog(RoutingContext.class); private final static Log log = LogUtil.getLog(RoutingContext.class);
public static final int OPTION_NO_LOAD = 0; public static final int OPTION_NO_LOAD = 0;
public static final int OPTION_SMART_LOAD = 1; public static final int OPTION_SMART_LOAD = 1;
@ -73,6 +73,8 @@ public class RoutingContext {
// 5. debug information (package accessor) // 5. debug information (package accessor)
public TileStatistics global = new TileStatistics(); public TileStatistics global = new TileStatistics();
// updated by route planner in bytes
public int memoryOverhead = 0;
long timeToLoad = 0; long timeToLoad = 0;
long timeToLoadHeaders = 0; long timeToLoadHeaders = 0;
long timeToFindInitialSegments = 0; long timeToFindInitialSegments = 0;
@ -707,21 +709,7 @@ public class RoutingContext {
} }
} }
protected static class TileStatistics { static int getEstimatedSize(RouteDataObject o) {
public int size = 0;
public int allRoutes = 0;
public int coordinates = 0;
@Override
public String toString() {
return "All routes " + allRoutes +
" size " + (size / 1024f) + " KB coordinates " + coordinates + " ratio coord " + (((float)size) / coordinates)
+ " ratio routes " + (((float)size) / allRoutes);
}
public void addObject(RouteDataObject o) {
allRoutes++;
coordinates += o.getPointsLength() * 2;
// calculate size // calculate size
int sz = 0; int sz = 0;
sz += 8 + 4; // overhead sz += 8 + 4; // overhead
@ -751,9 +739,28 @@ public class RoutingContext {
} }
} }
// Standard overhead? // Standard overhead?
size += sz * 3.5; return (int) (sz * 3.5);
// size += coordinates * 20;
} }
protected static class TileStatistics {
public int size = 0;
public int allRoutes = 0;
public int coordinates = 0;
@Override
public String toString() {
return "All routes " + allRoutes +
" size " + (size / 1024f) + " KB coordinates " + coordinates + " ratio coord " + (((float)size) / coordinates)
+ " ratio routes " + (((float)size) / allRoutes);
}
public void addObject(RouteDataObject o) {
allRoutes++;
coordinates += o.getPointsLength() * 2;
size += getEstimatedSize(o);
}
} }
} }

View file

@ -43,7 +43,7 @@
<!-- obstacle tag="highway" value="traffic_signals" penalty="35", penalty measured in seconds --> <!-- obstacle tag="highway" value="traffic_signals" penalty="35", penalty measured in seconds -->
<routingProfile name="car" baseProfile="car" restrictionsAware="true" minDefaultSpeed="45.0" maxDefaultSpeed="130.0" <routingProfile name="car" baseProfile="car" restrictionsAware="true" minDefaultSpeed="45.0" maxDefaultSpeed="130.0"
leftTurn="20" rightTurn="15" roundaboutTurn="20" followSpeedLimitations="true" onewayAware="true"> leftTurn="0" rightTurn="0" roundaboutTurn="0" followSpeedLimitations="true" onewayAware="true">
<!-- <!--
<attribute name="useDynamicRoadPrioritising" value="true" /> <attribute name="useDynamicRoadPrioritising" value="true" />
<attribute name="dynamicRoadPriorityDistance" value="0" /> <attribute name="dynamicRoadPriorityDistance" value="0" />