Refactoring routing a bit

This commit is contained in:
Victor Shcherb 2011-07-03 17:32:24 +02:00
parent 3bbc1e49ac
commit dfca6a94d3
5 changed files with 255 additions and 252 deletions

View file

@ -144,16 +144,17 @@ public class BicycleRouter extends VehicleRouter {
return 9; return 9;
} }
public double calculateTurnTime(int middley, int middlex, int x, int y, RouteSegment segment, RouteSegment next, int j) { public double calculateTurnTime(RouteSegment segment, RouteSegment next, int segmentEnd) {
boolean lineAreNotConnected = j < segment.road.getPointsLength() - 1 || next.segmentStart != 0; boolean end = (segmentEnd == segment.road.getPointsLength() - 1 || segmentEnd == 0);
if (lineAreNotConnected) { boolean start = next.segmentStart == 0;
if (end) {
if(!start){
return 5; return 5;
} else {
if (next.road.getPointsLength() > 1) {
return 5;
}
} }
return 0; return 0;
} else {
return 5;
}
} }
} }

View file

@ -32,7 +32,7 @@ public class BinaryRoutePlanner {
private final static boolean PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true; private final static boolean PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true;
private final BinaryMapIndexReader[] map; private final BinaryMapIndexReader[] map;
private int HEURISTIC_COEFFICIENT = 3; private static int DEFAULT_HEURISTIC_COEFFICIENT = 3;
private static final Log log = LogUtil.getLog(BinaryRoutePlanner.class); private static final Log log = LogUtil.getLog(BinaryRoutePlanner.class);
@ -142,26 +142,19 @@ public class BinaryRoutePlanner {
return road; return road;
} }
public int roadPriorityComparator(double o1DistanceFromStart, double o1DistanceToEnd,
double o2DistanceFromStart, double o2DistanceToEnd) {
// f(x) = g(x) + h(x) --- g(x) - distanceFromStart, h(x) - distanceToEnd (not exact)
return Double.compare(o1DistanceFromStart + HEURISTIC_COEFFICIENT * o1DistanceToEnd,
o2DistanceFromStart + HEURISTIC_COEFFICIENT * o2DistanceToEnd);
}
// TODO write unit tests // TODO write unit tests
// TODO add information about turns // TODO add information about turns
// TODO think about u-turn // TODO think about u-turn
// TODO fix roundabout // TODO fix roundabout (?)
// TODO access // TODO access
// TODO bicycle router (?)
// TODO fastest/shortest way // TODO fastest/shortest way
/** /**
* Calculate route between start.segmentEnd and end.segmentStart (using A* algorithm) * Calculate route between start.segmentEnd and end.segmentStart (using A* algorithm)
* return list of segments * return list of segments
*/ */
public List<RouteSegmentResult> searchRoute(RoutingContext ctx, RouteSegment start, RouteSegment end) throws IOException { public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, RouteSegment start, RouteSegment end) throws IOException {
// measure time // measure time
ctx.timeToLoad = 0; ctx.timeToLoad = 0;
@ -172,24 +165,21 @@ public class BinaryRoutePlanner {
Comparator<RouteSegment> segmentsComparator = new Comparator<RouteSegment>(){ Comparator<RouteSegment> segmentsComparator = new Comparator<RouteSegment>(){
@Override @Override
public int compare(RouteSegment o1, RouteSegment o2) { public int compare(RouteSegment o1, RouteSegment o2) {
return roadPriorityComparator(o1.distanceFromStart, o1.distanceToEnd, o2.distanceFromStart, o2.distanceToEnd); return ctx.roadPriorityComparator(o1.distanceFromStart, o1.distanceToEnd, o2.distanceFromStart, o2.distanceToEnd);
} }
}; };
PriorityQueue<RouteSegment> graphSegments = new PriorityQueue<RouteSegment>(50, segmentsComparator); PriorityQueue<RouteSegment> graphSegments = new PriorityQueue<RouteSegment>(50, segmentsComparator);
// initialize temporary lists to calculate not forbidden ways at way intersections
ArrayList<RouteSegment> segmentsToVisitPrescripted = new ArrayList<RouteSegment>(5);
ArrayList<RouteSegment> segmentsToVisitNotForbidden = new ArrayList<RouteSegment>(5);
// Set to not visit one segment twice (stores road.id << X + segmentStart) // Set to not visit one segment twice (stores road.id << X + segmentStart)
TLongHashSet visitedSegments = new TLongHashSet(); TLongHashSet visitedSegments = new TLongHashSet();
int endX = end.road.getPoint31XTile(end.segmentEnd); int targetEndX = end.road.getPoint31XTile(end.segmentEnd);
int endY = end.road.getPoint31YTile(end.segmentEnd); int targetEndY = end.road.getPoint31YTile(end.segmentEnd);
int startX = start.road.getPoint31XTile(start.segmentStart); int startX = start.road.getPoint31XTile(start.segmentStart);
int startY = start.road.getPoint31YTile(start.segmentStart); int startY = start.road.getPoint31YTile(start.segmentStart);
// 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)
start.distanceToEnd = squareRootDist(startX, startY, endX, endY) / ctx.router.getMaxDefaultSpeed(); start.distanceToEnd = squareRootDist(startX, startY, targetEndX, targetEndY) / ctx.router.getMaxDefaultSpeed();
// add start segment to priority queue // add start segment to priority queue
graphSegments.add(start); graphSegments.add(start);
@ -240,8 +230,6 @@ public class BinaryRoutePlanner {
if(end.road.getId() == road.getId() && end.segmentStart == middle){ if(end.road.getId() == road.getId() && end.segmentStart == middle){
finalRoute = segment; finalRoute = segment;
} }
// collect time for obstacles
double obstaclesTime = 0;
// Go through all point of the way and find ways to continue // Go through all point of the way and find ways to continue
while(finalRoute == null && ((!oneway && minus) || plus)) { while(finalRoute == null && ((!oneway && minus) || plus)) {
@ -281,16 +269,40 @@ public class BinaryRoutePlanner {
// 3. get intersected ways // 3. get intersected ways
RouteSegment next = ctx.routes.get(l); RouteSegment next = ctx.routes.get(l);
if (next != null) { if (next != null) {
int x = road.getPoint31XTile(j);
int y = road.getPoint31YTile(j);
double distOnRoadToPass = squareRootDist(x, y, middlex, middley);
double distToFinalPoint = squareRootDist(x, y, targetEndX, targetEndY);
processIntersectionsWithWays(ctx, graphSegments, visitedSegments, distOnRoadToPass, distToFinalPoint,
segment, road, d == 0, j, next);
}
}
}
segmentsToVisitPrescripted.clear();
segmentsToVisitNotForbidden.clear(); // 4. Route is found : collect all segments and prepare result
return prepareResult(ctx, start, end, startNanoTime, finalRoute);
}
private void processIntersectionsWithWays(RoutingContext ctx, PriorityQueue<RouteSegment> graphSegments,
TLongHashSet visitedSegments, double distOnRoadToPass, double distToFinalPoint,
RouteSegment segment, BinaryMapDataObject road, boolean firstOfSegment, int segmentEnd, RouteSegment next) {
// This variables can be in routing context
// initialize temporary lists to calculate not forbidden ways at way intersections
ArrayList<RouteSegment> segmentsToVisitPrescripted = new ArrayList<RouteSegment>(5);
ArrayList<RouteSegment> segmentsToVisitNotForbidden = new ArrayList<RouteSegment>(5);
// collect time for obstacles
double obstaclesTime = 0;
boolean exclusiveRestriction = false; boolean exclusiveRestriction = false;
// 3.1 calculate time for obstacles (bumps, traffic_signals, level_crossing) // 3.1 calculate time for obstacles (bumps, traffic_signals, level_crossing)
if (d != 0) { if (firstOfSegment) {
RouteSegment possibleObstacle = next; RouteSegment possibleObstacle = next;
while (possibleObstacle != null) { while (possibleObstacle != null) {
ctx.router.defineObstacle(possibleObstacle.road, possibleObstacle.segmentStart); obstaclesTime += ctx.router.defineObstacle(possibleObstacle.road, possibleObstacle.segmentStart);
possibleObstacle = possibleObstacle.next; possibleObstacle = possibleObstacle.next;
} }
} }
@ -310,15 +322,11 @@ public class BinaryRoutePlanner {
} }
if (type == -1 && exclusiveRestriction) { if (type == -1 && exclusiveRestriction) {
// next = next.next; continue; // next = next.next; continue;
} else if(type == MapRenderingTypes.RESTRICTION_NO_LEFT_TURN || } else if (type == MapRenderingTypes.RESTRICTION_NO_LEFT_TURN || type == MapRenderingTypes.RESTRICTION_NO_RIGHT_TURN
type == MapRenderingTypes.RESTRICTION_NO_RIGHT_TURN || || type == MapRenderingTypes.RESTRICTION_NO_STRAIGHT_ON || type == MapRenderingTypes.RESTRICTION_NO_U_TURN) {
type == MapRenderingTypes.RESTRICTION_NO_STRAIGHT_ON ||
type == MapRenderingTypes.RESTRICTION_NO_U_TURN){
// next = next.next; continue; // next = next.next; continue;
} else { } else {
double distanceToEnd = distToFinalPoint / ctx.router.getMaxDefaultSpeed();
int x = road.getPoint31XTile(j);
int y = road.getPoint31YTile(j);
// 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
@ -327,18 +335,14 @@ public class BinaryRoutePlanner {
speed = ctx.router.getMinDefaultSpeed(); speed = ctx.router.getMinDefaultSpeed();
} }
double distanceFromStart = segment.distanceFromStart + squareRootDist(x, y, middlex, middley) / speed; double distanceFromStart = segment.distanceFromStart + distOnRoadToPass / speed;
// calculate turn time // calculate turn time
distanceFromStart += ctx.router.calculateTurnTime(middley, middlex, x, y, segment, next, j); distanceFromStart += ctx.router.calculateTurnTime(segment, next, segmentEnd);
// add obstacles time // add obstacles time
distanceFromStart += obstaclesTime; distanceFromStart += obstaclesTime;
if (next.parentRoute == null
double distanceToEnd = squareRootDist(x, y, endX, endY) / ctx.router.getMaxDefaultSpeed(); || ctx.roadPriorityComparator(next.distanceFromStart, next.distanceToEnd, distanceFromStart, distanceToEnd) > 0) {
if(next.parentRoute == null ||
roadPriorityComparator(next.distanceFromStart, next.distanceToEnd,
distanceFromStart, distanceToEnd) > 0){
next.distanceFromStart = distanceFromStart; next.distanceFromStart = distanceFromStart;
next.distanceToEnd = distanceToEnd; next.distanceToEnd = distanceToEnd;
if (next.parentRoute != null) { if (next.parentRoute != null) {
@ -347,7 +351,7 @@ public class BinaryRoutePlanner {
} }
// put additional information to recover whole route after // put additional information to recover whole route after
next.parentRoute = segment; next.parentRoute = segment;
next.parentSegmentEnd = j; next.parentSegmentEnd = segmentEnd;
if (type == -1) { if (type == -1) {
// case no restriction // case no restriction
segmentsToVisitNotForbidden.add(next); segmentsToVisitNotForbidden.add(next);
@ -359,7 +363,6 @@ public class BinaryRoutePlanner {
} }
} }
} }
} }
next = next.next; next = next.next;
@ -373,13 +376,6 @@ public class BinaryRoutePlanner {
graphSegments.add(s); graphSegments.add(s);
} }
} }
}
}
// 4. Route is found : collect all segments and prepare result
return prepareResult(ctx, start, end, startNanoTime, finalRoute);
}
@ -518,21 +514,32 @@ public class BinaryRoutePlanner {
public static class RoutingContext { public static class RoutingContext {
TLongObjectMap<BinaryMapDataObject> idObjects = new TLongObjectHashMap<BinaryMapDataObject>(); // parameters of routing
TLongObjectMap<RouteSegment> routes = new TLongObjectHashMap<RouteSegment>(); public int heuristicCoefficient = DEFAULT_HEURISTIC_COEFFICIENT;
public VehicleRouter router = new CarRouter(); public VehicleRouter router = new CarRouter();
//
TLongObjectMap<BinaryMapDataObject> idObjects = new TLongObjectHashMap<BinaryMapDataObject>();
TLongObjectMap<RouteSegment> routes = new TLongObjectHashMap<RouteSegment>();
TIntSet loadedTiles = new TIntHashSet(); TIntSet loadedTiles = new TIntHashSet();
// set collection to not null to monitor visited ways
public RouteSegmentVisitor visitor = null;
// debug information
long timeToLoad = 0; long timeToLoad = 0;
long timeToCalculate = 0; long timeToCalculate = 0;
int visitedSegments = 0; int visitedSegments = 0;
// callback of processing segments
public RouteSegmentVisitor visitor = null;
public Collection<BinaryMapDataObject> values(){ public Collection<BinaryMapDataObject> values(){
return idObjects.valueCollection(); return idObjects.valueCollection();
} }
public int roadPriorityComparator(double o1DistanceFromStart, double o1DistanceToEnd,
double o2DistanceFromStart, double o2DistanceToEnd) {
// f(x) = g(x) + h(x) --- g(x) - distanceFromStart, h(x) - distanceToEnd (not exact)
return Double.compare(o1DistanceFromStart + heuristicCoefficient * o1DistanceToEnd,
o2DistanceFromStart + heuristicCoefficient * o2DistanceToEnd);
}
} }
public static class RouteSegment { public static class RouteSegment {

View file

@ -73,8 +73,7 @@ public class CarRouter extends VehicleRouter {
} }
public boolean isOneWay(int highwayAttributes) { public boolean isOneWay(int highwayAttributes) {
return MapRenderingTypes.isOneWayWay(highwayAttributes) || return MapRenderingTypes.isOneWayWay(highwayAttributes) || MapRenderingTypes.isRoundabout(highwayAttributes);
MapRenderingTypes.isRoundabout(highwayAttributes);
} }
/** /**
@ -115,9 +114,9 @@ public class CarRouter extends VehicleRouter {
return speed * priority; return speed * priority;
} }
/** /**
* Used for A* routing to calculate g(x) * Used for A* routing to calculate g(x)
*
* @return minimal speed at road * @return minimal speed at road
*/ */
public double getMinDefaultSpeed() { public double getMinDefaultSpeed() {
@ -126,28 +125,24 @@ public class CarRouter extends VehicleRouter {
/** /**
* Used for A* routing to predict h(x) : it should be < (!) any g(x) * Used for A* routing to predict h(x) : it should be < (!) any g(x)
*
* @return maximum speed to calculate shortest distance * @return maximum speed to calculate shortest distance
*/ */
public double getMaxDefaultSpeed() { public double getMaxDefaultSpeed() {
return 30; return 30;
} }
public double calculateTurnTime(RouteSegment segment, RouteSegment next, int segmentEnd) {
public double calculateTurnTime(int middley, int middlex, int x, int y, RouteSegment segment, RouteSegment next, int j) { boolean end = (segmentEnd == segment.road.getPointsLength() - 1 || segmentEnd == 0);
boolean lineAreNotConnected = j < segment.road.getPointsLength() - 1 || next.segmentStart != 0; boolean start = next.segmentStart == 0;
if(lineAreNotConnected){ if (end) {
return 25; if(!start){
} else { return 15;
if (next.road.getPointsLength() > 1) {
double a1 = Math.atan2(y - middley, x - middlex);
double a2 = Math.atan2(y - next.road.getPoint31YTile(1), x - next.road.getPoint31XTile(1));
double diff = Math.abs(a1 - a2);
if (diff > Math.PI / 2 && diff < 3 * Math.PI / 2) {
return 25;
}
}
} }
return 0; return 0;
} else {
return 25;
}
} }
} }

View file

@ -144,7 +144,7 @@ public class PedestrianRouter extends VehicleRouter {
return 2; return 2;
} }
public double calculateTurnTime(int middley, int middlex, int x, int y, RouteSegment segment, RouteSegment next, int j) { public double calculateTurnTime(RouteSegment segment, RouteSegment next, int j) {
return 0; return 0;
} }

View file

@ -58,5 +58,5 @@ public abstract class VehicleRouter {
/** /**
* Calculate turn time * Calculate turn time
*/ */
public abstract double calculateTurnTime(int middley, int middlex, int x, int y, RouteSegment segment, RouteSegment next, int j) ; public abstract double calculateTurnTime(RouteSegment segment, RouteSegment next, int segmentEnd) ;
} }