Introduce transport routing & remove legacy planner
This commit is contained in:
parent
8137a46439
commit
b67f4a8621
10 changed files with 441 additions and 607 deletions
|
@ -436,7 +436,7 @@ public class BinaryMapTransportReaderAdapter {
|
|||
}
|
||||
}
|
||||
dataObject.setId(did);
|
||||
dataObject.setLocation(MapUtils.getLatitudeFromTile(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, dy), MapUtils.getLongitudeFromTile(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, dx));
|
||||
dataObject.setLocation(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, dx, dy);
|
||||
return dataObject;
|
||||
}
|
||||
|
||||
|
@ -461,7 +461,7 @@ public class BinaryMapTransportReaderAdapter {
|
|||
req.cacheTypes.clear();
|
||||
|
||||
TransportStop dataObject = new TransportStop();
|
||||
dataObject.setLocation(MapUtils.getLatitudeFromTile(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, y), MapUtils.getLongitudeFromTile(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, x));
|
||||
dataObject.setLocation(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, x, y);
|
||||
dataObject.setFileOffset(shift);
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
|
|
|
@ -142,7 +142,7 @@ public class GeocodingUtilities {
|
|||
|
||||
|
||||
public List<GeocodingResult> reverseGeocodingSearch(RoutingContext ctx, double lat, double lon, boolean allowEmptyNames) throws IOException {
|
||||
RoutePlannerFrontEnd rp = new RoutePlannerFrontEnd(false);
|
||||
RoutePlannerFrontEnd rp = new RoutePlannerFrontEnd();
|
||||
List<GeocodingResult> lst = new ArrayList<GeocodingUtilities.GeocodingResult>();
|
||||
List<RouteSegmentPoint> listR = new ArrayList<BinaryRoutePlanner.RouteSegmentPoint>();
|
||||
rp.findRouteSegment(lat, lon, ctx, listR);
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
package net.osmand.data;
|
||||
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
public class TransportStop extends MapObject {
|
||||
private int[] referencesToRoutes = null;
|
||||
private Amenity amenity;
|
||||
public int distance;
|
||||
public int x31;
|
||||
public int y31;
|
||||
|
||||
|
||||
public TransportStop(){
|
||||
}
|
||||
|
@ -23,4 +28,15 @@ public class TransportStop extends MapObject {
|
|||
public void setAmenity(Amenity amenity) {
|
||||
this.amenity = amenity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocation(double latitude, double longitude) {
|
||||
super.setLocation(latitude, longitude);
|
||||
}
|
||||
|
||||
public void setLocation(int zoom, int dx, int dy) {
|
||||
x31 = dx << (31 - zoom);
|
||||
y31 = dy << (31 - zoom);
|
||||
setLocation(MapUtils.getLatitudeFromTile(zoom, dy), MapUtils.getLongitudeFromTile(zoom, dx));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,580 +0,0 @@
|
|||
package net.osmand.router;
|
||||
|
||||
import gnu.trove.map.hash.TLongObjectHashMap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.binary.RouteDataObject;
|
||||
import net.osmand.osm.MapRenderingTypes;
|
||||
import net.osmand.router.BinaryRoutePlanner.FinalRouteSegment;
|
||||
import net.osmand.router.BinaryRoutePlanner.RouteSegment;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
public class BinaryRoutePlannerOld {
|
||||
|
||||
public static boolean PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true;
|
||||
private static final int REVERSE_WAY_RESTRICTION_ONLY = 1024;
|
||||
private static final int STANDARD_ROAD_IN_QUEUE_OVERHEAD = 900;
|
||||
|
||||
protected static final Log log = PlatformUtil.getLog(BinaryRoutePlannerOld.class);
|
||||
|
||||
private static final int ROUTE_POINTS = 11;
|
||||
|
||||
|
||||
private static double squareRootDist(int x1, int y1, int x2, int y2) {
|
||||
return MapUtils.squareRootDist31(x1, y1, x2, y2);
|
||||
// return measuredDist(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate route between start.segmentEnd and end.segmentStart (using A* algorithm)
|
||||
* return list of segments
|
||||
*/
|
||||
void searchRouteInternal(final RoutingContext ctx, RouteSegment start, RouteSegment end) throws IOException, InterruptedException {
|
||||
// measure time
|
||||
ctx.timeToLoad = 0;
|
||||
ctx.visitedSegments = 0;
|
||||
ctx.timeToCalculate = System.nanoTime();
|
||||
if(ctx.config.initialDirection != null) {
|
||||
ctx.firstRoadId = (start.getRoad().id << ROUTE_POINTS) + start.getSegmentStart();
|
||||
double plusDir = start.getRoad().directionRoute(start.getSegmentStart(), true);
|
||||
double diff = plusDir - ctx.config.initialDirection;
|
||||
if(Math.abs(MapUtils.alignAngleDifference(diff)) <= Math.PI / 3) {
|
||||
ctx.firstRoadDirection = 1;
|
||||
} else if(Math.abs(MapUtils.alignAngleDifference(diff - Math.PI)) <= Math.PI / 3) {
|
||||
ctx.firstRoadDirection = -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Initializing priority queue to visit way segments
|
||||
Comparator<RouteSegment> segmentsComparator = new Comparator<RouteSegment>(){
|
||||
@Override
|
||||
public int compare(RouteSegment o1, RouteSegment o2) {
|
||||
return ctx.roadPriorityComparator(o1.distanceFromStart, o1.distanceToEnd, o2.distanceFromStart, o2.distanceToEnd);
|
||||
}
|
||||
};
|
||||
|
||||
Comparator<RouteSegment> nonHeuristicSegmentsComparator = new Comparator<RouteSegment>(){
|
||||
@Override
|
||||
public int compare(RouteSegment o1, RouteSegment o2) {
|
||||
return roadPriorityComparator(o1.distanceFromStart, o1.distanceToEnd, o2.distanceFromStart, o2.distanceToEnd, 0.5);
|
||||
}
|
||||
};
|
||||
|
||||
PriorityQueue<RouteSegment> graphDirectSegments = new PriorityQueue<RouteSegment>(50, segmentsComparator);
|
||||
PriorityQueue<RouteSegment> graphReverseSegments = new PriorityQueue<RouteSegment>(50, segmentsComparator);
|
||||
|
||||
// Set to not visit one segment twice (stores road.id << X + segmentStart)
|
||||
TLongObjectHashMap<RouteSegment> visitedDirectSegments = new TLongObjectHashMap<RouteSegment>();
|
||||
TLongObjectHashMap<RouteSegment> visitedOppositeSegments = new TLongObjectHashMap<RouteSegment>();
|
||||
|
||||
boolean runRecalculation = ctx.previouslyCalculatedRoute != null && ctx.previouslyCalculatedRoute.size() > 0
|
||||
&& ctx.config.recalculateDistance != 0;
|
||||
if (runRecalculation) {
|
||||
RouteSegment previous = null;
|
||||
List<RouteSegmentResult> rlist = new ArrayList<RouteSegmentResult>();
|
||||
float distanceThreshold = ctx.config.recalculateDistance;
|
||||
float threshold = 0;
|
||||
for(RouteSegmentResult rr : ctx.previouslyCalculatedRoute) {
|
||||
threshold += rr.getDistance();
|
||||
if(threshold > distanceThreshold) {
|
||||
rlist.add(rr);
|
||||
}
|
||||
}
|
||||
runRecalculation = rlist.size() > 0;
|
||||
if (rlist.size() > 0) {
|
||||
for (RouteSegmentResult rr : rlist) {
|
||||
RouteSegment segment = new RouteSegment(rr.getObject(), rr.getEndPointIndex());
|
||||
if (previous != null) {
|
||||
previous.setParentRoute(segment);
|
||||
previous.setParentSegmentEnd(rr.getStartPointIndex());
|
||||
long t = (rr.getObject().getId() << ROUTE_POINTS) + segment.getSegmentStart();
|
||||
visitedOppositeSegments.put(t, segment);
|
||||
}
|
||||
previous = segment;
|
||||
}
|
||||
end = previous;
|
||||
}
|
||||
}
|
||||
|
||||
// for start : f(start) = g(start) + h(start) = 0 + h(start) = h(start)
|
||||
int targetEndX = end.road.getPoint31XTile(end.getSegmentStart());
|
||||
int targetEndY = end.road.getPoint31YTile(end.getSegmentStart());
|
||||
int startX = start.road.getPoint31XTile(start.getSegmentStart());
|
||||
int startY = start.road.getPoint31YTile(start.getSegmentStart());
|
||||
float estimatedDistance = (float) h(ctx, targetEndX, targetEndY, startX, startY);
|
||||
end.distanceToEnd = start.distanceToEnd = estimatedDistance;
|
||||
|
||||
graphDirectSegments.add(start);
|
||||
graphReverseSegments.add(end);
|
||||
|
||||
// Extract & analyze segment with min(f(x)) from queue while final segment is not found
|
||||
boolean inverse = false;
|
||||
boolean init = false;
|
||||
|
||||
PriorityQueue<RouteSegment> graphSegments;
|
||||
if(inverse) {
|
||||
graphSegments = graphReverseSegments;
|
||||
} else {
|
||||
graphSegments = graphDirectSegments;
|
||||
}
|
||||
while (!graphSegments.isEmpty()) {
|
||||
RouteSegment segment = graphSegments.poll();
|
||||
ctx.visitedSegments++;
|
||||
// for debug purposes
|
||||
if (ctx.visitor != null) {
|
||||
// ctx.visitor.visitSegment(segment, true);
|
||||
}
|
||||
updateCalculationProgress(ctx, graphDirectSegments, graphReverseSegments);
|
||||
boolean routeFound = false;
|
||||
if (!inverse) {
|
||||
routeFound = processRouteSegment(ctx, false, graphDirectSegments, visitedDirectSegments, targetEndX, targetEndY,
|
||||
segment, visitedOppositeSegments);
|
||||
} else {
|
||||
routeFound = processRouteSegment(ctx, true, graphReverseSegments, visitedOppositeSegments, startX, startY, segment,
|
||||
visitedDirectSegments);
|
||||
}
|
||||
if (graphReverseSegments.isEmpty() || graphDirectSegments.isEmpty() || routeFound) {
|
||||
break;
|
||||
}
|
||||
if(runRecalculation) {
|
||||
// nothing to do
|
||||
inverse = false;
|
||||
} else if (!init) {
|
||||
inverse = !inverse;
|
||||
init = true;
|
||||
} else if (ctx.planRouteIn2Directions()) {
|
||||
inverse = nonHeuristicSegmentsComparator.compare(graphDirectSegments.peek(), graphReverseSegments.peek()) > 0;
|
||||
if (graphDirectSegments.size() * 1.3 > graphReverseSegments.size()) {
|
||||
inverse = true;
|
||||
} else if (graphDirectSegments.size() < 1.3 * graphReverseSegments.size()) {
|
||||
inverse = false;
|
||||
}
|
||||
} else {
|
||||
// different strategy : use onedirectional graph
|
||||
inverse = ctx.getPlanRoadDirection() < 0;
|
||||
}
|
||||
if (inverse) {
|
||||
graphSegments = graphReverseSegments;
|
||||
} else {
|
||||
graphSegments = graphDirectSegments;
|
||||
}
|
||||
// check if interrupted
|
||||
if(ctx.calculationProgress != null && ctx.calculationProgress.isCancelled) {
|
||||
throw new InterruptedException("Route calculation interrupted");
|
||||
}
|
||||
}
|
||||
println("Result is found");
|
||||
printDebugMemoryInformation(ctx, graphDirectSegments, graphReverseSegments, visitedDirectSegments, visitedOppositeSegments);
|
||||
}
|
||||
|
||||
private void updateCalculationProgress(final RoutingContext ctx, PriorityQueue<RouteSegment> graphDirectSegments,
|
||||
PriorityQueue<RouteSegment> graphReverseSegments) {
|
||||
if(ctx.calculationProgress != null) {
|
||||
ctx.calculationProgress.reverseSegmentQueueSize = graphReverseSegments.size();
|
||||
ctx.calculationProgress.directSegmentQueueSize = graphDirectSegments.size();
|
||||
RouteSegment dirPeek = graphDirectSegments.peek();
|
||||
if(dirPeek != null) {
|
||||
ctx.calculationProgress.distanceFromBegin =
|
||||
Math.max(dirPeek.distanceFromStart, ctx.calculationProgress.distanceFromBegin);
|
||||
}
|
||||
RouteSegment revPeek = graphReverseSegments.peek();
|
||||
if(revPeek != null) {
|
||||
ctx.calculationProgress.distanceFromEnd =
|
||||
Math.max(revPeek.distanceFromStart, ctx.calculationProgress.distanceFromEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private double h(final RoutingContext ctx, int targetEndX, int targetEndY,
|
||||
int startX, int startY) {
|
||||
double distance = squareRootDist(startX, startY, targetEndX, targetEndY);
|
||||
return distance / ctx.getRouter().getMaxDefaultSpeed();
|
||||
}
|
||||
|
||||
protected static double h(RoutingContext ctx, double distToFinalPoint, RouteSegment next) {
|
||||
return distToFinalPoint / ctx.getRouter().getMaxDefaultSpeed();
|
||||
}
|
||||
|
||||
private static void println(String logMsg) {
|
||||
// log.info(logMsg);
|
||||
System.out.println(logMsg);
|
||||
}
|
||||
|
||||
private static void printInfo(String logMsg) {
|
||||
log.warn(logMsg);
|
||||
}
|
||||
|
||||
public void printDebugMemoryInformation(RoutingContext ctx, PriorityQueue<RouteSegment> graphDirectSegments, PriorityQueue<RouteSegment> graphReverseSegments,
|
||||
TLongObjectHashMap<RouteSegment> visitedDirectSegments,TLongObjectHashMap<RouteSegment> visitedOppositeSegments) {
|
||||
printInfo("Time to calculate : " + (System.nanoTime() - ctx.timeToCalculate) / 1e6 + ", time to load : " + ctx.timeToLoad / 1e6 + ", time to load headers : " + ctx.timeToLoadHeaders / 1e6);
|
||||
int maxLoadedTiles = Math.max(ctx.maxLoadedTiles, ctx.getCurrentlyLoadedTiles());
|
||||
printInfo("Current loaded tiles : " + ctx.getCurrentlyLoadedTiles() + ", maximum loaded tiles " + maxLoadedTiles);
|
||||
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);
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private boolean 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
|
||||
final RouteDataObject road = segment.road;
|
||||
final int middle = segment.getSegmentStart();
|
||||
float obstaclePlusTime = 0;
|
||||
float obstacleMinusTime = 0;
|
||||
|
||||
|
||||
// This is correct way of checking but it has problem with relaxing strategy
|
||||
// long ntf = (segment.road.getId() << ROUTE_POINTS) + segment.segmentStart;
|
||||
// visitedSegments.put(ntf, segment);
|
||||
// if (oppositeSegments.contains(ntf) && oppositeSegments.get(ntf) != null) {
|
||||
// RouteSegment opposite = oppositeSegments.get(ntf);
|
||||
// if (opposite.segmentStart == segment.segmentStart) {
|
||||
// if (reverseWaySearch) {
|
||||
// reverse : segment.parentSegmentEnd - segment.parentRoute
|
||||
// } else {
|
||||
// reverse : opposite.parentSegmentEnd - oppositie.parentRoute
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// 0. mark route segment as visited
|
||||
long nt = (road.getId() << ROUTE_POINTS) + middle;
|
||||
// avoid empty segments to connect but mark the point as visited
|
||||
visitedSegments.put(nt, null);
|
||||
|
||||
int oneway = ctx.getRouter().isOneWay(road);
|
||||
boolean minusAllowed;
|
||||
boolean plusAllowed;
|
||||
if(ctx.firstRoadId == nt) {
|
||||
if(ctx.firstRoadDirection < 0) {
|
||||
obstaclePlusTime += 500;
|
||||
} else if(ctx.firstRoadDirection > 0) {
|
||||
obstacleMinusTime += 500;
|
||||
}
|
||||
}
|
||||
if (!reverseWaySearch) {
|
||||
minusAllowed = oneway <= 0;
|
||||
plusAllowed = oneway >= 0;
|
||||
} else {
|
||||
minusAllowed = oneway >= 0;
|
||||
plusAllowed = oneway <= 0;
|
||||
}
|
||||
|
||||
// +/- diff from middle point
|
||||
int d = plusAllowed ? 1 : -1;
|
||||
if(segment.parentRoute != null) {
|
||||
if(plusAllowed && middle < segment.getRoad().getPointsLength() - 1) {
|
||||
obstaclePlusTime = (float) ctx.getRouter().calculateTurnTime(segment, segment.getRoad().getPointsLength() - 1,
|
||||
segment.parentRoute, segment.parentSegmentEnd);
|
||||
}
|
||||
if(minusAllowed && middle > 0) {
|
||||
obstacleMinusTime = (float) ctx.getRouter().calculateTurnTime(segment, 0,
|
||||
segment.parentRoute, segment.parentSegmentEnd);
|
||||
}
|
||||
}
|
||||
// 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 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;
|
||||
if (!minusAllowed && d > 0) {
|
||||
d++;
|
||||
} else if (!plusAllowed && d < 0) {
|
||||
d--;
|
||||
} else {
|
||||
if (d <= 0) {
|
||||
d = -d + 1;
|
||||
} else {
|
||||
d = -d;
|
||||
}
|
||||
}
|
||||
if (segmentEnd < 0) {
|
||||
minusAllowed = false;
|
||||
continue;
|
||||
}
|
||||
if (segmentEnd >= road.getPointsLength()) {
|
||||
plusAllowed = false;
|
||||
continue;
|
||||
}
|
||||
// if we found end point break cycle
|
||||
long nts = (road.getId() << ROUTE_POINTS) + segmentEnd;
|
||||
visitedSegments.put(nts, 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));
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
// int overhead = 0;
|
||||
// could be expensive calculation
|
||||
int overhead = (ctx.visitedSegments - ctx.relaxedSegments ) *
|
||||
STANDARD_ROAD_IN_QUEUE_OVERHEAD;
|
||||
if(overhead > ctx.config.memoryLimitation * 0.95){
|
||||
throw new OutOfMemoryError("There is no enough memory " + ctx.config.memoryLimitation/(1<<20) + " Mb");
|
||||
}
|
||||
RouteSegment next = ctx.loadRouteSegment(x, y, ctx.config.memoryLimitation - overhead);
|
||||
// 3. get intersected ways
|
||||
if (next != null) {
|
||||
// TO-DO U-Turn
|
||||
if((next == segment || next.road.id == road.id) && next.next == null) {
|
||||
// simplification if there is no real intersection
|
||||
continue;
|
||||
}
|
||||
// Using A* routing algorithm
|
||||
// g(x) - calculate distance to that point and calculate time
|
||||
|
||||
float priority = ctx.getRouter().defineSpeedPriority(road);
|
||||
float speed = ctx.getRouter().defineRoutingSpeed(road) * priority;
|
||||
if (speed == 0) {
|
||||
speed = ctx.getRouter().getMinDefaultSpeed() * priority;
|
||||
}
|
||||
float distOnRoadToPass = positive? posSegmentDist : negSegmentDist;
|
||||
float distStartObstacles = segment.distanceFromStart + ( positive ? obstaclePlusTime : obstacleMinusTime) +
|
||||
distOnRoadToPass / speed;
|
||||
|
||||
float distToFinalPoint = (float) squareRootDist(x, y, targetEndX, targetEndY);
|
||||
boolean routeFound = processIntersections(ctx, graphSegments, visitedSegments, oppositeSegments,
|
||||
distStartObstacles, distToFinalPoint, segment, segmentEnd, next, reverseWaySearch);
|
||||
if(routeFound){
|
||||
return routeFound;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private boolean proccessRestrictions(RoutingContext ctx, RouteDataObject road, RouteSegment inputNext, boolean reverseWay) {
|
||||
ctx.segmentsToVisitPrescripted.clear();
|
||||
ctx.segmentsToVisitNotForbidden.clear();
|
||||
boolean exclusiveRestriction = false;
|
||||
RouteSegment next = inputNext;
|
||||
if (!reverseWay && road.getRestrictionLength() == 0) {
|
||||
return false;
|
||||
}
|
||||
if(!ctx.getRouter().restrictionsAware()) {
|
||||
return false;
|
||||
}
|
||||
while (next != null) {
|
||||
int type = -1;
|
||||
if (!reverseWay) {
|
||||
for (int i = 0; i < road.getRestrictionLength(); i++) {
|
||||
if (road.getRestrictionId(i) == next.road.id) {
|
||||
type = road.getRestrictionType(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < next.road.getRestrictionLength(); i++) {
|
||||
int rt = next.road.getRestrictionType(i);
|
||||
long restrictedTo = next.road.getRestrictionId(i);
|
||||
if (restrictedTo == road.id) {
|
||||
type = rt;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if there is restriction only to the other than current road
|
||||
if (rt == MapRenderingTypes.RESTRICTION_ONLY_RIGHT_TURN || rt == MapRenderingTypes.RESTRICTION_ONLY_LEFT_TURN
|
||||
|| rt == MapRenderingTypes.RESTRICTION_ONLY_STRAIGHT_ON) {
|
||||
// check if that restriction applies to considered junk
|
||||
RouteSegment foundNext = inputNext;
|
||||
while (foundNext != null) {
|
||||
if (foundNext.getRoad().id == restrictedTo) {
|
||||
break;
|
||||
}
|
||||
foundNext = foundNext.next;
|
||||
}
|
||||
if (foundNext != null) {
|
||||
type = REVERSE_WAY_RESTRICTION_ONLY; // special constant
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type == REVERSE_WAY_RESTRICTION_ONLY) {
|
||||
// next = next.next; continue;
|
||||
} else if (type == -1 && exclusiveRestriction) {
|
||||
// next = next.next; continue;
|
||||
} else if (type == MapRenderingTypes.RESTRICTION_NO_LEFT_TURN || type == MapRenderingTypes.RESTRICTION_NO_RIGHT_TURN
|
||||
|| type == MapRenderingTypes.RESTRICTION_NO_STRAIGHT_ON || type == MapRenderingTypes.RESTRICTION_NO_U_TURN) {
|
||||
// next = next.next; continue;
|
||||
} else if (type == -1) {
|
||||
// case no restriction
|
||||
ctx.segmentsToVisitNotForbidden.add(next);
|
||||
} else {
|
||||
// case exclusive restriction (only_right, only_straight, ...)
|
||||
// 1. in case we are going backward we should not consider only_restriction
|
||||
// as exclusive because we have many "in" roads and one "out"
|
||||
// 2. in case we are going forward we have one "in" and many "out"
|
||||
if (!reverseWay) {
|
||||
exclusiveRestriction = true;
|
||||
ctx.segmentsToVisitNotForbidden.clear();
|
||||
ctx.segmentsToVisitPrescripted.add(next);
|
||||
} else {
|
||||
ctx.segmentsToVisitNotForbidden.add(next);
|
||||
}
|
||||
}
|
||||
next = next.next;
|
||||
}
|
||||
ctx.segmentsToVisitPrescripted.addAll(ctx.segmentsToVisitNotForbidden);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private boolean processIntersections(RoutingContext ctx, PriorityQueue<RouteSegment> graphSegments,
|
||||
TLongObjectHashMap<RouteSegment> visitedSegments, TLongObjectHashMap<RouteSegment> oppositeSegments,
|
||||
float distFromStart, float distToFinalPoint,
|
||||
RouteSegment segment, int segmentEnd, RouteSegment inputNext,
|
||||
boolean reverseWay) {
|
||||
|
||||
boolean thereAreRestrictions = proccessRestrictions(ctx, segment.road, inputNext, reverseWay);
|
||||
Iterator<RouteSegment> nextIterator = null;
|
||||
if (thereAreRestrictions) {
|
||||
nextIterator = ctx.segmentsToVisitPrescripted.iterator();
|
||||
}
|
||||
// Calculate possible ways to put into priority queue
|
||||
RouteSegment next = inputNext;
|
||||
boolean hasNext = nextIterator == null || nextIterator.hasNext();
|
||||
while (hasNext) {
|
||||
if (nextIterator != null) {
|
||||
next = nextIterator.next();
|
||||
}
|
||||
long nts = (next.road.getId() << ROUTE_POINTS) + next.getSegmentStart();
|
||||
|
||||
// 1. Check if opposite segment found so we can stop calculations
|
||||
if (oppositeSegments.contains(nts) && oppositeSegments.get(nts) != null) {
|
||||
// restrictions checked
|
||||
RouteSegment opposite = oppositeSegments.get(nts);
|
||||
// additional check if opposite way not the same as current one
|
||||
if (next.getSegmentStart() != segmentEnd ||
|
||||
opposite.getRoad().getId() != segment.getRoad().getId()) {
|
||||
FinalRouteSegment frs = new FinalRouteSegment(segment.getRoad(), segment.getSegmentStart());
|
||||
float distStartObstacles = segment.distanceFromStart;
|
||||
frs.setParentRoute(segment.getParentRoute());
|
||||
frs.setParentSegmentEnd(segment.getParentSegmentEnd());
|
||||
frs.reverseWaySearch = reverseWay;
|
||||
frs.distanceFromStart = opposite.distanceFromStart + distStartObstacles;
|
||||
RouteSegment op = new RouteSegment(segment.getRoad(), segmentEnd);
|
||||
op.setParentRoute(opposite);
|
||||
op.setParentSegmentEnd(next.getSegmentStart());
|
||||
frs.distanceToEnd = 0;
|
||||
frs.opposite = op;
|
||||
ctx.finalRouteSegment = frs;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// road.id could be equal on roundabout, but we should accept them
|
||||
boolean alreadyVisited = visitedSegments.contains(nts);
|
||||
if (!alreadyVisited) {
|
||||
float distanceToEnd = (float) h(ctx, distToFinalPoint, next);
|
||||
if (next.parentRoute == null
|
||||
|| ctx.roadPriorityComparator(next.distanceFromStart, next.distanceToEnd, distFromStart, distanceToEnd) > 0) {
|
||||
if (next.parentRoute != null) {
|
||||
// already in queue remove it
|
||||
if (!graphSegments.remove(next)) {
|
||||
// exist in different queue!
|
||||
next = new RouteSegment(next.getRoad(), next.getSegmentStart());
|
||||
}
|
||||
}
|
||||
next.distanceFromStart = distFromStart;
|
||||
next.distanceToEnd = distanceToEnd;
|
||||
// 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);
|
||||
}
|
||||
} else {
|
||||
// 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)
|
||||
if (distFromStart < next.distanceFromStart && next.road.id != segment.road.id) {
|
||||
// That code is incorrect (when segment is processed itself,
|
||||
// then it tries to make wrong u-turn) -
|
||||
// this situation should be very carefully checked in future (seems to be fixed)
|
||||
// System.out.println(segment.getRoad().getName() + " " + next.getRoad().getName());
|
||||
// System.out.println(next.distanceFromStart + " ! " + distFromStart);
|
||||
next.distanceFromStart = distFromStart;
|
||||
next.setParentRoute(segment);
|
||||
next.setParentSegmentEnd(segmentEnd);
|
||||
if (ctx.visitor != null) {
|
||||
// ctx.visitor.visitSegment(next, next.getSegmentStart(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// iterate to next road
|
||||
if (nextIterator == null) {
|
||||
next = next.next;
|
||||
hasNext = next != null;
|
||||
} else {
|
||||
hasNext = nextIterator.hasNext();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*public */static int roadPriorityComparator(double o1DistanceFromStart, double o1DistanceToEnd,
|
||||
double o2DistanceFromStart, double o2DistanceToEnd, double heuristicCoefficient ) {
|
||||
// f(x) = g(x) + h(x) --- g(x) - distanceFromStart, h(x) - distanceToEnd (not exact)
|
||||
return Double.compare(o1DistanceFromStart + heuristicCoefficient * o1DistanceToEnd,
|
||||
o2DistanceFromStart + heuristicCoefficient * o2DistanceToEnd);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,14 @@
|
|||
package net.osmand.router;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.NativeLibrary;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.binary.BinaryMapIndexReader;
|
||||
|
@ -15,24 +23,17 @@ import net.osmand.util.MapUtils;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class RoutePlannerFrontEnd {
|
||||
|
||||
private boolean useOldVersion;
|
||||
protected static final Log log = PlatformUtil.getLog(RoutePlannerFrontEnd.class);
|
||||
public boolean useSmartRouteRecalculation = true;
|
||||
|
||||
public RoutePlannerFrontEnd(boolean useOldVersion) {
|
||||
this.useOldVersion = useOldVersion;
|
||||
|
||||
public RoutePlannerFrontEnd() {
|
||||
this.useOldVersion = false;
|
||||
}
|
||||
|
||||
|
||||
public enum RouteCalculationMode {
|
||||
BASE,
|
||||
NORMAL,
|
||||
|
@ -345,11 +346,7 @@ public class RoutePlannerFrontEnd {
|
|||
} else {
|
||||
refreshProgressDistance(ctx);
|
||||
// Split into 2 methods to let GC work in between
|
||||
if (useOldVersion) {
|
||||
new BinaryRoutePlannerOld().searchRouteInternal(ctx, start, end);
|
||||
} else {
|
||||
ctx.finalRouteSegment = new BinaryRoutePlanner().searchRouteInternal(ctx, start, end, recalculationEnd);
|
||||
}
|
||||
ctx.finalRouteSegment = new BinaryRoutePlanner().searchRouteInternal(ctx, start, end, recalculationEnd);
|
||||
// 4. Route is found : collect all segments and prepare result
|
||||
return new RouteResultPreparation().prepareResult(ctx, ctx.finalRouteSegment);
|
||||
}
|
||||
|
|
|
@ -197,9 +197,6 @@ public class RoutingContext {
|
|||
return config.planRoadDirection;
|
||||
}
|
||||
|
||||
public void setPlanRoadDirection(int planRoadDirection) {
|
||||
config.planRoadDirection = planRoadDirection;
|
||||
}
|
||||
|
||||
public int roadPriorityComparator(double o1DistanceFromStart, double o1DistanceToEnd, double o2DistanceFromStart, double o2DistanceToEnd) {
|
||||
return BinaryRoutePlanner.roadPriorityComparator(o1DistanceFromStart, o1DistanceToEnd, o2DistanceFromStart, o2DistanceToEnd,
|
||||
|
|
|
@ -28,7 +28,6 @@ public class TestRouting {
|
|||
public static boolean TEST_WO_HEURISTIC = false;
|
||||
public static boolean TEST_BOTH_DIRECTION = false;
|
||||
public static NativeLibrary lib = null;
|
||||
public static boolean oldRouting = false;
|
||||
private static String vehicle = "car";
|
||||
|
||||
|
||||
|
@ -203,7 +202,7 @@ public class TestRouting {
|
|||
return;
|
||||
}
|
||||
RoutingConfiguration rconfig = config.build(vehicle, MEMORY_TEST_LIMIT);
|
||||
RoutePlannerFrontEnd router = new RoutePlannerFrontEnd(oldRouting);
|
||||
RoutePlannerFrontEnd router = new RoutePlannerFrontEnd();
|
||||
RoutingContext ctx = router.buildRoutingContext(rconfig,
|
||||
lib, rs);
|
||||
String skip = parser.getAttributeValue("", "skip_comment");
|
||||
|
@ -308,7 +307,7 @@ public class TestRouting {
|
|||
long ts = System.currentTimeMillis();
|
||||
Builder config = RoutingConfiguration.getDefault();
|
||||
RoutingConfiguration rconfig = config.build(vehicle, MEMORY_TEST_LIMIT);
|
||||
RoutePlannerFrontEnd router = new RoutePlannerFrontEnd(oldRouting);
|
||||
RoutePlannerFrontEnd router = new RoutePlannerFrontEnd();
|
||||
RoutingContext ctx = router.buildRoutingContext(rconfig, lib, rs);
|
||||
RouteSegment startSegment = router.findRouteSegment(startLat, startLon, ctx, null);
|
||||
RouteSegment endSegment = router.findRouteSegment(endLat, endLon, ctx, null);
|
||||
|
|
|
@ -0,0 +1,405 @@
|
|||
package net.osmand.router;
|
||||
|
||||
import gnu.trove.iterator.TIntIterator;
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
import gnu.trove.map.hash.TLongObjectHashMap;
|
||||
import gnu.trove.set.hash.TLongHashSet;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
import net.osmand.binary.BinaryMapIndexReader;
|
||||
import net.osmand.binary.RouteDataObject;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.data.QuadRect;
|
||||
import net.osmand.data.QuadTree;
|
||||
import net.osmand.data.TransportRoute;
|
||||
import net.osmand.data.TransportStop;
|
||||
import net.osmand.router.BinaryRoutePlanner.FinalRouteSegment;
|
||||
import net.osmand.router.BinaryRoutePlanner.RouteSegment;
|
||||
import net.osmand.router.BinaryRoutePlanner.RouteSegmentPoint;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
public class TransportRoutePlanner {
|
||||
|
||||
public void searchRouteInternal(final TransportRoutingContext ctx, TransportRouteSegment start, TransportRouteSegment end,
|
||||
RouteSegment recalculationEnd) throws InterruptedException, IOException {
|
||||
Comparator<TransportRouteSegment> nonHeuristicSegmentsComparator = new NonHeuristicSegmentsComparator();
|
||||
PriorityQueue<TransportRouteSegment> graphDirectSegments = new PriorityQueue<TransportRouteSegment>(50, new SegmentsComparator(
|
||||
ctx));
|
||||
PriorityQueue<TransportRouteSegment> graphReverseSegments = new PriorityQueue<TransportRouteSegment>(50, new SegmentsComparator(
|
||||
ctx));
|
||||
// Set to not visit one segment twice (stores road.id << X + segmentStart)
|
||||
TLongObjectHashMap<TransportRouteSegment> visitedDirectSegments = new TLongObjectHashMap<TransportRouteSegment>();
|
||||
TLongObjectHashMap<TransportRouteSegment> visitedOppositeSegments = new TLongObjectHashMap<TransportRouteSegment>();
|
||||
|
||||
|
||||
// Extract & analyze segment with min(f(x)) from queue while final segment is not found
|
||||
boolean forwardSearch = true;
|
||||
|
||||
PriorityQueue<TransportRouteSegment> graphSegments = graphDirectSegments;
|
||||
|
||||
FinalRouteSegment finalSegment = null;
|
||||
boolean onlyBackward = ctx.getPlanRoadDirection() < 0;
|
||||
boolean onlyForward = ctx.getPlanRoadDirection() > 0;
|
||||
while (!graphSegments.isEmpty()) {
|
||||
TransportRouteSegment segment = graphSegments.poll();
|
||||
// TODO break when it is final segment
|
||||
// if (segment instanceof FinalRouteSegment) {
|
||||
// finalSegment = (FinalRouteSegment) segment;
|
||||
// break;
|
||||
// }
|
||||
ctx.visitedSegments++;
|
||||
if (forwardSearch) {
|
||||
boolean doNotAddIntersections = onlyBackward;
|
||||
processRouteSegment(ctx, false, graphDirectSegments, visitedDirectSegments, segment,
|
||||
visitedOppositeSegments, doNotAddIntersections);
|
||||
} else {
|
||||
boolean doNotAddIntersections = onlyForward;
|
||||
processRouteSegment(ctx, true, graphReverseSegments, visitedOppositeSegments, segment,
|
||||
visitedDirectSegments, doNotAddIntersections);
|
||||
}
|
||||
updateCalculationProgress(ctx, graphDirectSegments, graphReverseSegments);
|
||||
|
||||
checkIfGraphIsEmpty(ctx, ctx.getPlanRoadDirection() <= 0, graphReverseSegments, end,
|
||||
visitedOppositeSegments, "Route is not found to selected target point.");
|
||||
checkIfGraphIsEmpty(ctx, ctx.getPlanRoadDirection() >= 0, graphDirectSegments, start,
|
||||
visitedDirectSegments, "Route is not found from selected start point.");
|
||||
if (ctx.planRouteIn2Directions()) {
|
||||
forwardSearch = (nonHeuristicSegmentsComparator.compare(graphDirectSegments.peek(),
|
||||
graphReverseSegments.peek()) < 0);
|
||||
} else {
|
||||
// different strategy : use onedirectional graph
|
||||
forwardSearch = onlyForward;
|
||||
if (onlyBackward && !graphDirectSegments.isEmpty()) {
|
||||
forwardSearch = true;
|
||||
}
|
||||
if (onlyForward && !graphReverseSegments.isEmpty()) {
|
||||
forwardSearch = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (forwardSearch) {
|
||||
graphSegments = graphDirectSegments;
|
||||
} else {
|
||||
graphSegments = graphReverseSegments;
|
||||
}
|
||||
// check if interrupted
|
||||
if (ctx.calculationProgress != null && ctx.calculationProgress.isCancelled) {
|
||||
throw new InterruptedException("Route calculation interrupted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void checkIfGraphIsEmpty(TransportRoutingContext ctx, boolean b,
|
||||
PriorityQueue<TransportRouteSegment> graphReverseSegments, TransportRouteSegment end,
|
||||
TLongObjectHashMap<TransportRouteSegment> visitedOppositeSegments, String string) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
|
||||
private void updateCalculationProgress(TransportRoutingContext ctx,
|
||||
PriorityQueue<TransportRouteSegment> graphDirectSegments, PriorityQueue<TransportRouteSegment> graphReverseSegments) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
private static int sleft = MapUtils.get31TileNumberX(4.7495);
|
||||
private static int sright = MapUtils.get31TileNumberX(4.8608);
|
||||
private static int stop = MapUtils.get31TileNumberY(52.3395);
|
||||
private static int sbottom = MapUtils.get31TileNumberY(52.2589);
|
||||
private static int szoom = 15;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void processRouteSegment(final TransportRoutingContext ctx, boolean reverseWaySearch,
|
||||
PriorityQueue<TransportRouteSegment> graphSegments, TLongObjectHashMap<TransportRouteSegment> visitedSegments,
|
||||
TransportRouteSegment segment, TLongObjectHashMap<TransportRouteSegment> oppositeSegments, boolean doNotAddIntersections) throws IOException {
|
||||
final TransportRoute road = segment.road;
|
||||
BinaryMapIndexReader reader = ctx.map.keySet().iterator().next();
|
||||
List<TransportStop> transportStops = reader.searchTransportIndex(BinaryMapIndexReader.buildSearchTransportRequest(sleft, sright, stop, sbottom,
|
||||
-1, null));
|
||||
for(TransportStop s : transportStops) {
|
||||
int[] referencesToRoutes = s.getReferencesToRoutes();
|
||||
TIntObjectHashMap<TransportRoute> routes = reader.getTransportRoutes(referencesToRoutes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
File fl = new File(System.getProperty("maps.dir"), "Netherlands_amstelveen.obf");
|
||||
RandomAccessFile raf = new RandomAccessFile(fl, "r");
|
||||
BinaryMapIndexReader reader = new BinaryMapIndexReader(raf, fl);
|
||||
|
||||
LatLon start = new LatLon(52.28094, 4.853248);
|
||||
LatLon end = new LatLon(52.320988, 4.87256);
|
||||
TransportRoutingContext ctx = new TransportRoutingContext(reader);
|
||||
TransportRoutePlanner planner = new TransportRoutePlanner();
|
||||
planner.buildRoute(ctx, start, end);
|
||||
|
||||
}
|
||||
|
||||
private void buildRoute(TransportRoutingContext ctx, LatLon start, LatLon end) throws IOException {
|
||||
double limit = 1000;
|
||||
BinaryMapIndexReader reader = ctx.map.keySet().iterator().next();
|
||||
|
||||
List<TransportRouteSegment> startStops = ctx.getTransportStops(start);
|
||||
List<TransportRouteSegment> endStops = ctx.getTransportStops(end);
|
||||
|
||||
TLongObjectHashMap<TransportRouteSegment> endSegments = new TLongObjectHashMap<TransportRouteSegment>();
|
||||
for(TransportRouteSegment s : endStops) {
|
||||
endSegments.put(s.getId(), s);
|
||||
}
|
||||
PriorityQueue<TransportRouteSegment> queue = new PriorityQueue<TransportRoutePlanner.TransportRouteSegment>();
|
||||
queue.addAll(startStops);
|
||||
while(!queue.isEmpty()) {
|
||||
TransportRouteSegment segment = queue.poll();
|
||||
long l = segment.getId();
|
||||
for (int i = 0; i < segment.getLength() - segment.segStart; i++) {
|
||||
TransportRouteSegment finish = endSegments.get(l+i);
|
||||
if(finish != null){
|
||||
System.out.println(segment + " " + finish);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SegmentsComparator implements Comparator<TransportRouteSegment> {
|
||||
final TransportRoutingContext ctx;
|
||||
|
||||
public SegmentsComparator(TransportRoutingContext ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(TransportRouteSegment o1, TransportRouteSegment o2) {
|
||||
return BinaryRoutePlanner.roadPriorityComparator(o1.distanceFromStart, o1.distanceToEnd,
|
||||
o2.distanceFromStart, o2.distanceToEnd, ctx.config.heuristicCoefficient);
|
||||
}
|
||||
}
|
||||
|
||||
private static class NonHeuristicSegmentsComparator implements Comparator<TransportRouteSegment> {
|
||||
public NonHeuristicSegmentsComparator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(TransportRouteSegment o1, TransportRouteSegment o2) {
|
||||
return BinaryRoutePlanner.
|
||||
roadPriorityComparator(o1.distanceFromStart, o1.distanceToEnd, o2.distanceFromStart, o2.distanceToEnd, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public RouteSegment initRouteSegment(final TransportRoutingContext ctx, TransportRouteSegment segment, boolean positiveDirection) {
|
||||
// if (segment.getSegmentStart() == 0 && !positiveDirection && segment.getRoad().getPointsLength() > 0) {
|
||||
// segment = loadSameSegment(ctx, segment, 1);
|
||||
//// } else if (segment.getSegmentStart() == segment.getRoad().getPointsLength() - 1 && positiveDirection && segment.getSegmentStart() > 0) {
|
||||
// // assymetric cause we calculate initial point differently (segmentStart means that point is between ]segmentStart-1, segmentStart]
|
||||
// } else if (segment.getSegmentStart() > 0 && positiveDirection) {
|
||||
// segment = loadSameSegment(ctx, segment, segment.getSegmentStart() - 1);
|
||||
// }
|
||||
// if (segment == null) {
|
||||
// return null;
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class TransportRouteSegment {
|
||||
public double distanceToEnd;
|
||||
final short segStart;
|
||||
final TransportRoute road;
|
||||
private static final int SHIFT = 10; // assume less than 1024 stops
|
||||
|
||||
TransportRouteSegment parentRoute = null;
|
||||
float distanceFromStart = 0;
|
||||
|
||||
public TransportRouteSegment(TransportRoute road, int stopIndex) {
|
||||
this.road = road;
|
||||
this.segStart = (short) stopIndex;
|
||||
}
|
||||
|
||||
|
||||
public int getLength() {
|
||||
return road.getForwardStops().size();
|
||||
}
|
||||
|
||||
|
||||
public long getId() {
|
||||
long l = road.getId() << SHIFT;
|
||||
if(l < 0 ) {
|
||||
throw new IllegalStateException("too long id " + road.getId());
|
||||
}
|
||||
if(segStart >= (1 << SHIFT)) {
|
||||
throw new IllegalStateException("too many stops " + road.getId() + " " + segStart);
|
||||
}
|
||||
return l + segStart;
|
||||
}
|
||||
|
||||
|
||||
public int getDepth() {
|
||||
if(parentRoute != null) {
|
||||
return parentRoute.getDepth() + 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Route stop: %s %s", road, road.getForwardStops().get(segStart));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TransportRoutingContext {
|
||||
|
||||
public final int walkRadius = 5000; // meters from start/end/intermediate locations
|
||||
public int searchThreshold = 10; // don't search stops beyond searchThreshold*dist(start, end) radius
|
||||
|
||||
public int visitedSegments;
|
||||
public RoutingConfiguration config;
|
||||
public RouteCalculationProgress calculationProgress;
|
||||
public TLongObjectHashMap<TransportStop> visitedTransportStops = new TLongObjectHashMap<TransportStop>();
|
||||
private TIntArrayList visitedTiles = new TIntArrayList();
|
||||
private static final int ZOOM_TO_LOAD_TILES = 14;
|
||||
|
||||
public QuadTree<TransportRouteSegment> quadTree =
|
||||
new QuadTree<TransportRouteSegment>(new QuadRect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE), 8, 0.55f);
|
||||
public final Map<BinaryMapIndexReader, TIntObjectHashMap<TransportRoute>> map =
|
||||
new LinkedHashMap<BinaryMapIndexReader, TIntObjectHashMap<TransportRoute>>();
|
||||
|
||||
private final int walkRaidusIn31;
|
||||
|
||||
|
||||
public TransportRoutingContext(BinaryMapIndexReader... readers) {
|
||||
walkRaidusIn31 = (int) (walkRadius / MapUtils.getTileDistanceWidth(31));
|
||||
for (BinaryMapIndexReader r : readers) {
|
||||
map.put(r, new TIntObjectHashMap<TransportRoute>());
|
||||
}
|
||||
}
|
||||
|
||||
public List<TransportRouteSegment> getTransportStops(LatLon start) throws IOException {
|
||||
int y = MapUtils.get31TileNumberY(start.getLatitude());
|
||||
int x = MapUtils.get31TileNumberX(start.getLongitude());
|
||||
return getTransportStops(x, y);
|
||||
}
|
||||
|
||||
public List<TransportRouteSegment> getTransportStops(int x, int y) throws IOException {
|
||||
return loadNativeTransportStops(x, y);
|
||||
}
|
||||
|
||||
private List<TransportRouteSegment> loadNativeTransportStops(int sx, int sy) throws IOException {
|
||||
List<TransportRouteSegment> allstops = new ArrayList<TransportRouteSegment>();
|
||||
int lx = (sx - walkRaidusIn31 ) >> (31 - ZOOM_TO_LOAD_TILES);
|
||||
int rx = (sx + walkRaidusIn31 ) >> (31 - ZOOM_TO_LOAD_TILES);
|
||||
int ty = (sy - walkRaidusIn31 ) >> (31 - ZOOM_TO_LOAD_TILES);
|
||||
int by = (sy + walkRaidusIn31 ) >> (31 - ZOOM_TO_LOAD_TILES);
|
||||
for(int x = lx; x <= rx; x++) {
|
||||
for(int y = ty; y <= by; y++) {
|
||||
loadTile(x, y);
|
||||
}
|
||||
}
|
||||
quadTree.queryInBox(new QuadRect(sx - walkRaidusIn31, sy - walkRaidusIn31, sx + walkRaidusIn31,
|
||||
sy + walkRadius), allstops);
|
||||
return allstops;
|
||||
}
|
||||
|
||||
|
||||
private void loadTile(int x, int y) throws IOException {
|
||||
int tileId = x << (ZOOM_TO_LOAD_TILES + 1) + y;
|
||||
if(visitedTiles.contains(tileId)) {
|
||||
return;
|
||||
}
|
||||
int pz = (31 - ZOOM_TO_LOAD_TILES);
|
||||
SearchRequest<TransportStop> sr = BinaryMapIndexReader.buildSearchTransportRequest(x << pz, (x + 1) << pz,
|
||||
y << pz, (y + 1) << pz, -1, null);
|
||||
TIntArrayList allPoints = new TIntArrayList();
|
||||
TIntArrayList allPointsUnique = new TIntArrayList();
|
||||
for(BinaryMapIndexReader r : map.keySet()) {
|
||||
sr.clearSearchResults();
|
||||
List<TransportStop> stops = r.searchTransportIndex(sr);
|
||||
for(TransportStop s : stops) {
|
||||
if(!visitedTransportStops.contains(s.getId())) {
|
||||
visitedTransportStops.put(s.getId(), s);
|
||||
allPoints.addAll(s.getReferencesToRoutes());
|
||||
|
||||
}
|
||||
}
|
||||
makeUnique(allPoints, allPointsUnique);
|
||||
if(allPointsUnique.size() > 0) {
|
||||
loadTransportSegments(allPointsUnique, r, stops);
|
||||
}
|
||||
}
|
||||
visitedTiles.add(tileId);
|
||||
}
|
||||
|
||||
private void loadTransportSegments(TIntArrayList allPointsUnique, BinaryMapIndexReader r,
|
||||
List<TransportStop> stops) throws IOException {
|
||||
TIntObjectHashMap<TransportRoute> routes = r.getTransportRoutes(allPointsUnique.toArray());
|
||||
map.get(r).putAll(routes);
|
||||
for(TransportStop s : stops) {
|
||||
for(int ref : s.getReferencesToRoutes()) {
|
||||
TransportRoute route = routes.get(ref);
|
||||
if(route != null) {
|
||||
int stopIndex = -1;
|
||||
for(int k = 0; k < route.getForwardStops().size(); k++) {
|
||||
TransportStop st = route.getForwardStops().get(k);
|
||||
if(st.x31 == s.x31 && s.y31 == st.y31) {
|
||||
stopIndex = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(stopIndex != -1) {
|
||||
TransportRouteSegment segment = new TransportRouteSegment(route, stopIndex);
|
||||
quadTree.insert(segment, s.x31, s.y31);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void makeUnique(TIntArrayList allPoints, TIntArrayList allPointsUnique) {
|
||||
allPoints.sort();
|
||||
int p = 0;
|
||||
TIntIterator it = allPoints.iterator();
|
||||
while(it.hasNext()) {
|
||||
int nxt = it.next();
|
||||
if(p != nxt) {
|
||||
allPointsUnique.add(nxt);
|
||||
p = nxt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getPlanRoadDirection() {
|
||||
return config.planRoadDirection;
|
||||
}
|
||||
|
||||
public SearchRequest<TransportStop> getBuildRequest(LatLon start) {
|
||||
int sy = MapUtils.get31TileNumberY(start.getLatitude());
|
||||
int sx = MapUtils.get31TileNumberX(start.getLongitude());
|
||||
int w = (int) (walkRadius / MapUtils.getTileDistanceWidth(31));
|
||||
int h = (int) (walkRadius / MapUtils.getTileDistanceWidth(31));
|
||||
return BinaryMapIndexReader.buildSearchTransportRequest(sx - w, sx + w, sy - h, sy + h, -1, null);
|
||||
}
|
||||
|
||||
public VehicleRouter getRouter() {
|
||||
return config.router;
|
||||
}
|
||||
|
||||
public boolean planRouteIn2Directions() {
|
||||
return config.planRoadDirection == 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -59,7 +59,7 @@ public class RouteResultPreparationTest {
|
|||
|
||||
RandomAccessFile raf = new RandomAccessFile(fl, "r");
|
||||
|
||||
fe = new RoutePlannerFrontEnd(false);
|
||||
fe = new RoutePlannerFrontEnd();
|
||||
RoutingConfiguration.Builder builder = RoutingConfiguration.getDefault();
|
||||
Map<String, String> params = new LinkedHashMap<String, String>();
|
||||
params.put("car", "true");
|
||||
|
|
|
@ -60,7 +60,7 @@ public class RouteTestingTest {
|
|||
public void testRouting() throws Exception {
|
||||
String fl = "src/test/resources/Routing_test.obf";
|
||||
RandomAccessFile raf = new RandomAccessFile(fl, "r");
|
||||
RoutePlannerFrontEnd fe = new RoutePlannerFrontEnd(false);
|
||||
RoutePlannerFrontEnd fe = new RoutePlannerFrontEnd();
|
||||
|
||||
BinaryMapIndexReader[] binaryMapIndexReaders = { new BinaryMapIndexReader(raf, new File(fl)) };
|
||||
RoutingConfiguration.Builder builder = RoutingConfiguration.getDefault();
|
||||
|
|
Loading…
Reference in a new issue