Introduce concept of loading/unloading tiles
This commit is contained in:
parent
16ff5ef587
commit
3f12b33e78
4 changed files with 290 additions and 138 deletions
|
@ -17,7 +17,6 @@ import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteDataBlock;
|
||||||
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteDataBox;
|
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteDataBox;
|
||||||
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteEncodingRule;
|
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteEncodingRule;
|
||||||
import net.osmand.binary.OsmandOdb.RouteData;
|
import net.osmand.binary.OsmandOdb.RouteData;
|
||||||
import net.osmand.data.MapAlgorithms;
|
|
||||||
import net.osmand.osm.MapUtils;
|
import net.osmand.osm.MapUtils;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package net.osmand.router;
|
package net.osmand.router;
|
||||||
|
|
||||||
|
import gnu.trove.iterator.TIntObjectIterator;
|
||||||
import gnu.trove.map.hash.TLongObjectHashMap;
|
import gnu.trove.map.hash.TLongObjectHashMap;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -26,6 +27,7 @@ import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
||||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion;
|
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion;
|
||||||
import net.osmand.osm.MapRenderingTypes;
|
import net.osmand.osm.MapRenderingTypes;
|
||||||
import net.osmand.osm.MapUtils;
|
import net.osmand.osm.MapUtils;
|
||||||
|
import net.osmand.router.RoutingContext.RoutingTile;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
|
@ -90,7 +92,7 @@ public class BinaryRoutePlanner {
|
||||||
int px = MapUtils.get31TileNumberX(lon);
|
int px = MapUtils.get31TileNumberX(lon);
|
||||||
int py = MapUtils.get31TileNumberY(lat);
|
int py = MapUtils.get31TileNumberY(lat);
|
||||||
List<RouteDataObject> dataObjects = new ArrayList<RouteDataObject>();
|
List<RouteDataObject> dataObjects = new ArrayList<RouteDataObject>();
|
||||||
loadRoutes(ctx, px,py, dataObjects);
|
RoutingTile tl = loadRoutes(ctx, px,py, dataObjects);
|
||||||
|
|
||||||
RouteSegment road = null;
|
RouteSegment road = null;
|
||||||
double sdist = 0;
|
double sdist = 0;
|
||||||
|
@ -122,12 +124,15 @@ public class BinaryRoutePlanner {
|
||||||
if(ro.pointTypes.size() > j) {
|
if(ro.pointTypes.size() > j) {
|
||||||
ro.pointTypes.add(j, null);
|
ro.pointTypes.add(j, null);
|
||||||
}
|
}
|
||||||
registerRouteDataObject(ctx, ro);
|
|
||||||
sdist = currentsDist;
|
sdist = currentsDist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(road != null) {
|
||||||
|
// re-register the best road because one more point was inserted
|
||||||
|
registerRouteDataObject(ctx, road.getRoad(), tl);
|
||||||
|
}
|
||||||
return road;
|
return road;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +152,6 @@ public class BinaryRoutePlanner {
|
||||||
* return list of segments
|
* return list of segments
|
||||||
*/
|
*/
|
||||||
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, RouteSegment start, RouteSegment end) throws IOException {
|
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, RouteSegment start, RouteSegment end) throws IOException {
|
||||||
boolean relaxingStrategy = true;
|
|
||||||
// measure time
|
// measure time
|
||||||
ctx.timeToLoad = 0;
|
ctx.timeToLoad = 0;
|
||||||
ctx.visitedSegments = 0;
|
ctx.visitedSegments = 0;
|
||||||
|
@ -199,7 +203,6 @@ public class BinaryRoutePlanner {
|
||||||
while (!graphSegments.isEmpty()) {
|
while (!graphSegments.isEmpty()) {
|
||||||
RouteSegment segment = graphSegments.poll();
|
RouteSegment segment = graphSegments.poll();
|
||||||
|
|
||||||
|
|
||||||
ctx.visitedSegments++;
|
ctx.visitedSegments++;
|
||||||
// for debug purposes
|
// for debug purposes
|
||||||
if (ctx.visitor != null) {
|
if (ctx.visitor != null) {
|
||||||
|
@ -235,13 +238,16 @@ public class BinaryRoutePlanner {
|
||||||
} else {
|
} else {
|
||||||
graphSegments = graphDirectSegments;
|
graphSegments = graphDirectSegments;
|
||||||
}
|
}
|
||||||
if (relaxingStrategy) {
|
|
||||||
ctx.relaxedIteration++;
|
ctx.garbageCollectorIteration++;
|
||||||
if (ctx.relaxedIteration > 100) {
|
if (ctx.garbageCollectorIteration > RoutingContext.ITERATIONS_TO_RUN_GC ||
|
||||||
ctx.relaxedIteration = 0;
|
ctx.getCurrentlyLoadedTiles() > 30) {
|
||||||
|
ctx.garbageCollectorIteration = 0;
|
||||||
|
if (ctx.isUseRelaxingStrategy()) {
|
||||||
relaxNotNeededSegments(ctx, graphDirectSegments, true);
|
relaxNotNeededSegments(ctx, graphDirectSegments, true);
|
||||||
relaxNotNeededSegments(ctx, graphReverseSegments, false);
|
relaxNotNeededSegments(ctx, graphReverseSegments, false);
|
||||||
}
|
}
|
||||||
|
unloadUnusedTiles(ctx, 30);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printDebugMemoryInformation(ctx, graphDirectSegments, graphReverseSegments, visitedDirectSegments, visitedOppositeSegments);
|
printDebugMemoryInformation(ctx, graphDirectSegments, graphReverseSegments, visitedDirectSegments, visitedOppositeSegments);
|
||||||
|
@ -251,49 +257,47 @@ public class BinaryRoutePlanner {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SegmentStat {
|
private void unloadUnusedTiles(RoutingContext ctx, int desirableSize) {
|
||||||
String name;
|
// now delete all
|
||||||
Set<Float> set = new TreeSet<Float>();
|
List<RoutingTile> list = new ArrayList<RoutingContext.RoutingTile>();
|
||||||
|
TIntObjectIterator<RoutingTile> it = ctx.tiles.iterator();
|
||||||
public SegmentStat(String name) {
|
int loaded = 0;
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addNumber(float v) {
|
|
||||||
set.add(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
int segmentation = 7;
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append(name).append(" (").append(set.size()).append(") : ");
|
|
||||||
float s = set.size() / ((float) segmentation);
|
|
||||||
int k = 0, number = 0;
|
|
||||||
float limit = 0, value = 0;
|
|
||||||
Iterator<Float> it = set.iterator();
|
|
||||||
while(it.hasNext()) {
|
while(it.hasNext()) {
|
||||||
k++;
|
it.advance();
|
||||||
number++;
|
RoutingTile t = it.value();
|
||||||
value += it.next();
|
if(t.isLoaded()) {
|
||||||
if (k >= limit) {
|
list.add(t);
|
||||||
limit += s;
|
loaded++;
|
||||||
sb.append(value / number).append(" ");
|
|
||||||
number = 0;
|
|
||||||
value = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(number > 0) {
|
|
||||||
sb.append(value / number).append(" ");
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
ctx.maxLoadedTiles = Math.max(ctx.maxLoadedTiles, ctx.getCurrentlyLoadedTiles());
|
||||||
|
Collections.sort(list, new Comparator<RoutingTile>() {
|
||||||
|
private int pow(int base, int pw) {
|
||||||
|
int r = 1;
|
||||||
|
for (int i = 0; i < pw; i++) {
|
||||||
|
r *= base;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int compare(RoutingTile o1, RoutingTile o2) {
|
||||||
|
int v1 = (o1.access + 1) * pow(10, o1.getUnloadCont() -1);
|
||||||
|
int v2 = (o2.access + 1) * pow(10, o2.getUnloadCont() -1);
|
||||||
|
return v1 < v2 ? -1 : (v1 == v2 ? 0 : 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
int toUnload = Math.max(loaded / 5, loaded - desirableSize);
|
||||||
|
for (int i = 0; i < loaded; i++) {
|
||||||
|
list.get(i).access = 0;
|
||||||
|
if (i < toUnload) {
|
||||||
|
ctx.unloadTile(list.get(i), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void relaxNotNeededSegments(RoutingContext ctx, PriorityQueue<RouteSegment> graphSegments, boolean inverse) {
|
private void relaxNotNeededSegments(RoutingContext ctx, PriorityQueue<RouteSegment> graphSegments, boolean inverse) {
|
||||||
|
|
||||||
RouteSegment next = graphSegments.peek();
|
RouteSegment next = graphSegments.peek();
|
||||||
double mine = next.distanceToEnd;
|
double mine = next.distanceToEnd;
|
||||||
// int before = graphSegments.size();
|
// int before = graphSegments.size();
|
||||||
|
@ -338,17 +342,27 @@ public class BinaryRoutePlanner {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerRouteDataObject(final RoutingContext ctx, RouteDataObject o) {
|
private void registerRouteDataObject(final RoutingContext ctx, RouteDataObject o, RoutingTile suggestedTile ) {
|
||||||
RouteDataObject old = ctx.idObjects.get(o.id);
|
if(!ctx.getRouter().acceptLine(o)){
|
||||||
// sometimes way are presented only partially in one index
|
|
||||||
if ((old != null && old.pointsX.size() >= o.pointsX.size()) || (!ctx.getRouter().acceptLine(o))) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ctx.idObjects.put(o.id, o);
|
RoutingTile tl = suggestedTile;
|
||||||
|
RouteDataObject old = tl.idObjects.get(o.id);
|
||||||
|
// sometimes way is present only partially in one index
|
||||||
|
if (old != null && old.pointsX.size() >= o.pointsX.size()) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
for (int j = 0; j < o.pointsX.size(); j++) {
|
for (int j = 0; j < o.pointsX.size(); j++) {
|
||||||
long l = (((long) o.pointsX.getQuick(j)) << 31) + (long) o.pointsY.getQuick(j);
|
int x = o.pointsX.getQuick(j);
|
||||||
|
int y = o.pointsY.getQuick(j);
|
||||||
|
if(!tl.checkContains(x, y)){
|
||||||
|
// don't register in different tiles
|
||||||
|
// in order to throw out tile object easily
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
long l = (((long) x) << 31) + (long) y;
|
||||||
RouteSegment segment = new RouteSegment(o , j);
|
RouteSegment segment = new RouteSegment(o , j);
|
||||||
RouteSegment prev = ctx.routes.get(l);
|
RouteSegment prev = tl.routes.get(l);
|
||||||
boolean i = true;
|
boolean i = true;
|
||||||
if (prev != null) {
|
if (prev != null) {
|
||||||
if (old == null) {
|
if (old == null) {
|
||||||
|
@ -371,7 +385,7 @@ public class BinaryRoutePlanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i) {
|
if (i) {
|
||||||
ctx.routes.put(l, segment);
|
tl.routes.put(l, segment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,12 +395,14 @@ public class BinaryRoutePlanner {
|
||||||
System.out.println(logMsg);
|
System.out.println(logMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void printDebugMemoryInformation(RoutingContext ctx,
|
public void printDebugMemoryInformation(RoutingContext ctx, PriorityQueue<RouteSegment> graphDirectSegments, PriorityQueue<RouteSegment> graphReverseSegments,
|
||||||
PriorityQueue<RouteSegment> graphDirectSegments, PriorityQueue<RouteSegment> graphReverseSegments,
|
|
||||||
TLongObjectHashMap<RouteSegment> visitedDirectSegments,TLongObjectHashMap<RouteSegment> visitedOppositeSegments) {
|
TLongObjectHashMap<RouteSegment> visitedDirectSegments,TLongObjectHashMap<RouteSegment> visitedOppositeSegments) {
|
||||||
println("Time to calculate : " + (System.nanoTime() - ctx.timeToCalculate) / 1e6 + ", time to load : " + ctx.timeToLoad / 1e6);
|
println("Time to calculate : " + (System.nanoTime() - ctx.timeToCalculate) / 1e6 + ", time to load : " + ctx.timeToLoad / 1e6);
|
||||||
println("Loaded tiles : " + ctx.loadedTiles.size() + ", visited roads " + ctx.visitedSegments);
|
println("Current loaded tiles : " + ctx.getCurrentlyLoadedTiles() + ", maximum loaded tiles " + ctx.maxLoadedTiles);
|
||||||
println("Relaxed roads: " + ctx.relaxedSegments);
|
println("Loaded tiles : " + ctx.loadedTiles + ", unloaded tiles " + ctx.unloadedTiles +
|
||||||
|
" (distinct " + ctx.distinctUnloadedTiles.size()+") "+ ", loaded \"unloaded\" tiles "
|
||||||
|
+ ctx.loadedPrevUnloadedTiles );
|
||||||
|
println("Visited roads, " + ctx.visitedSegments + ", relaxed roads " + ctx.relaxedSegments);
|
||||||
if (graphDirectSegments != null && graphReverseSegments != null) {
|
if (graphDirectSegments != null && graphReverseSegments != null) {
|
||||||
println("Priority queues sizes : " + graphDirectSegments.size() + "/" + graphReverseSegments.size());
|
println("Priority queues sizes : " + graphDirectSegments.size() + "/" + graphReverseSegments.size());
|
||||||
}
|
}
|
||||||
|
@ -396,13 +412,14 @@ public class BinaryRoutePlanner {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadRoutes(final RoutingContext ctx, int tile31X, int tile31Y, final List<RouteDataObject> toFillIn) {
|
public RoutingTile loadRoutes(final RoutingContext ctx, int tile31X, int tile31Y, final List<RouteDataObject> toFillIn) {
|
||||||
int zoomToLoad = 31 - ctx.getZoomToLoadTileWithRoads();
|
int zoomToLoad = 31 - ctx.getZoomToLoadTileWithRoads();
|
||||||
int tileX = tile31X >> zoomToLoad;
|
int tileX = tile31X >> zoomToLoad;
|
||||||
int tileY = tile31Y >> zoomToLoad;
|
int tileY = tile31Y >> zoomToLoad;
|
||||||
int tileC = (tileX << ctx.getZoomToLoadTileWithRoads()) + tileY;
|
final RoutingTile tile = ctx.getRoutingTile(tile31X, tile31Y);
|
||||||
if (ctx.loadedTiles.contains(tileC) && toFillIn == null) {
|
if (tile.isLoaded() && toFillIn == null) {
|
||||||
return;
|
tile.access++;
|
||||||
|
return tile;
|
||||||
}
|
}
|
||||||
long now = System.nanoTime();
|
long now = System.nanoTime();
|
||||||
ResultMatcher<RouteDataObject> matcher = new ResultMatcher<RouteDataObject>() {
|
ResultMatcher<RouteDataObject> matcher = new ResultMatcher<RouteDataObject>() {
|
||||||
|
@ -413,7 +430,7 @@ public class BinaryRoutePlanner {
|
||||||
toFillIn.add(o);
|
toFillIn.add(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
registerRouteDataObject(ctx, o);
|
registerRouteDataObject(ctx, o, tile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,8 +448,13 @@ public class BinaryRoutePlanner {
|
||||||
throw new RuntimeException("Loading data exception", e);
|
throw new RuntimeException("Loading data exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.loadedTiles.add(tileC);
|
ctx.loadedTiles++;
|
||||||
|
if(tile.isUnloaded()) {
|
||||||
|
ctx.loadedPrevUnloadedTiles++;
|
||||||
|
}
|
||||||
|
tile.setLoaded();
|
||||||
ctx.timeToLoad += (System.nanoTime() - now);
|
ctx.timeToLoad += (System.nanoTime() - now);
|
||||||
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -502,9 +524,8 @@ public class BinaryRoutePlanner {
|
||||||
// 2. calculate point and try to load neighbor ways if they are not loaded
|
// 2. calculate point and try to load neighbor ways if they are not loaded
|
||||||
int x = road.getPoint31XTile(segmentEnd);
|
int x = road.getPoint31XTile(segmentEnd);
|
||||||
int y = road.getPoint31YTile(segmentEnd);
|
int y = road.getPoint31YTile(segmentEnd);
|
||||||
loadRoutes(ctx, x, y, null);
|
RoutingTile tile = loadRoutes(ctx, x, y, null);
|
||||||
|
|
||||||
// TO-DO ADD-INFO attach add information about speed cameras here
|
|
||||||
// 2.1 calculate possible obstacle plus time
|
// 2.1 calculate possible obstacle plus time
|
||||||
if(d > 0){
|
if(d > 0){
|
||||||
obstaclePlusTime += ctx.getRouter().defineObstacle(road, segmentEnd);
|
obstaclePlusTime += ctx.getRouter().defineObstacle(road, segmentEnd);
|
||||||
|
@ -514,11 +535,11 @@ public class BinaryRoutePlanner {
|
||||||
|
|
||||||
|
|
||||||
long l = (((long) x) << 31) + (long) y;
|
long l = (((long) x) << 31) + (long) y;
|
||||||
RouteSegment next = ctx.routes.get(l);
|
RouteSegment next = tile.routes.get(l);
|
||||||
// 3. get intersected ways
|
// 3. get intersected ways
|
||||||
if (next != null) {
|
if (next != null) {
|
||||||
// TO-DO U-Turn
|
// TO-DO U-Turn
|
||||||
if(next == segment && next.next == null) {
|
if((next == segment || next.road.id == road.id) && next.next == null) {
|
||||||
// simplification if there is no real intersection
|
// simplification if there is no real intersection
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -708,43 +729,6 @@ public class BinaryRoutePlanner {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RouteSegment {
|
|
||||||
final int segmentStart;
|
|
||||||
final RouteDataObject road;
|
|
||||||
// needed to store intersection of routes
|
|
||||||
RouteSegment next = null;
|
|
||||||
|
|
||||||
// search context (needed for searching route)
|
|
||||||
// Initially it should be null (!) because it checks was it segment visited before
|
|
||||||
RouteSegment parentRoute = null;
|
|
||||||
int parentSegmentEnd = 0;
|
|
||||||
|
|
||||||
// distance measured in time (seconds)
|
|
||||||
double distanceFromStart = 0;
|
|
||||||
double distanceToEnd = 0;
|
|
||||||
|
|
||||||
public RouteSegment(RouteDataObject road, int segmentStart) {
|
|
||||||
this.road = road;
|
|
||||||
this.segmentStart = segmentStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RouteSegment getNext() {
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSegmentStart() {
|
|
||||||
return segmentStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RouteDataObject getRoad() {
|
|
||||||
return road;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTestName(){
|
|
||||||
return String.format("s%.2f e%.2f", ((float)distanceFromStart), ((float)distanceToEnd));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to prepare final result
|
* Helper method to prepare final result
|
||||||
*/
|
*/
|
||||||
|
@ -818,15 +802,6 @@ public class BinaryRoutePlanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public interface RouteSegmentVisitor {
|
|
||||||
|
|
||||||
public void visitSegment(RouteSegment segment, boolean poll);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*public */static int roadPriorityComparator(double o1DistanceFromStart, double o1DistanceToEnd,
|
/*public */static int roadPriorityComparator(double o1DistanceFromStart, double o1DistanceToEnd,
|
||||||
double o2DistanceFromStart, double o2DistanceToEnd, double heuristicCoefficient ) {
|
double o2DistanceFromStart, double o2DistanceToEnd, double heuristicCoefficient ) {
|
||||||
// f(x) = g(x) + h(x) --- g(x) - distanceFromStart, h(x) - distanceToEnd (not exact)
|
// f(x) = g(x) + h(x) --- g(x) - distanceFromStart, h(x) - distanceToEnd (not exact)
|
||||||
|
@ -835,5 +810,87 @@ public class BinaryRoutePlanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface RouteSegmentVisitor {
|
||||||
|
|
||||||
|
public void visitSegment(RouteSegment segment, boolean poll);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RouteSegment {
|
||||||
|
final int segmentStart;
|
||||||
|
final RouteDataObject road;
|
||||||
|
// needed to store intersection of routes
|
||||||
|
RouteSegment next = null;
|
||||||
|
|
||||||
|
// search context (needed for searching route)
|
||||||
|
// Initially it should be null (!) because it checks was it segment visited before
|
||||||
|
RouteSegment parentRoute = null;
|
||||||
|
int parentSegmentEnd = 0;
|
||||||
|
|
||||||
|
// distance measured in time (seconds)
|
||||||
|
double distanceFromStart = 0;
|
||||||
|
double distanceToEnd = 0;
|
||||||
|
|
||||||
|
public RouteSegment(RouteDataObject road, int segmentStart) {
|
||||||
|
this.road = road;
|
||||||
|
this.segmentStart = segmentStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteSegment getNext() {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSegmentStart() {
|
||||||
|
return segmentStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteDataObject getRoad() {
|
||||||
|
return road;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTestName(){
|
||||||
|
return String.format("s%.2f e%.2f", ((float)distanceFromStart), ((float)distanceToEnd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class SegmentStat {
|
||||||
|
String name;
|
||||||
|
Set<Float> set = new TreeSet<Float>();
|
||||||
|
|
||||||
|
public SegmentStat(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addNumber(float v) {
|
||||||
|
set.add(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
int segmentation = 7;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(name).append(" (").append(set.size()).append(") : ");
|
||||||
|
float s = set.size() / ((float) segmentation);
|
||||||
|
int k = 0, number = 0;
|
||||||
|
float limit = 0, value = 0;
|
||||||
|
Iterator<Float> it = set.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
k++;
|
||||||
|
number++;
|
||||||
|
value += it.next();
|
||||||
|
if (k >= limit) {
|
||||||
|
limit += s;
|
||||||
|
sb.append(value / number).append(" ");
|
||||||
|
number = 0;
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(number > 0) {
|
||||||
|
sb.append(value / number).append(" ");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package net.osmand.router;
|
package net.osmand.router;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
import gnu.trove.map.TLongObjectMap;
|
import gnu.trove.map.TLongObjectMap;
|
||||||
|
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||||
import gnu.trove.map.hash.TLongObjectHashMap;
|
import gnu.trove.map.hash.TLongObjectHashMap;
|
||||||
import gnu.trove.set.TIntSet;
|
import gnu.trove.set.TIntSet;
|
||||||
import gnu.trove.set.TLongSet;
|
import gnu.trove.set.TLongSet;
|
||||||
|
@ -18,10 +20,12 @@ import net.osmand.router.BinaryRoutePlanner.RouteSegmentVisitor;
|
||||||
public class RoutingContext {
|
public class RoutingContext {
|
||||||
private static int DEFAULT_HEURISTIC_COEFFICIENT = 1;
|
private static int DEFAULT_HEURISTIC_COEFFICIENT = 1;
|
||||||
private static int ZOOM_TO_LOAD_TILES = 13; // 12?, 14?
|
private static int ZOOM_TO_LOAD_TILES = 13; // 12?, 14?
|
||||||
|
public static int ITERATIONS_TO_RUN_GC = 100;
|
||||||
|
|
||||||
// 1. parameters of routing and different tweaks
|
// 1. parameters of routing and different tweaks
|
||||||
private int heuristicCoefficient = DEFAULT_HEURISTIC_COEFFICIENT;
|
private double heuristicCoefficient = DEFAULT_HEURISTIC_COEFFICIENT;
|
||||||
private int zoomToLoadTileWithRoads = ZOOM_TO_LOAD_TILES;
|
private int zoomToLoadTileWithRoads = ZOOM_TO_LOAD_TILES;
|
||||||
|
private boolean useRelaxingStrategy = true;
|
||||||
// null - 2 ways, true - direct way, false - reverse way
|
// null - 2 ways, true - direct way, false - reverse way
|
||||||
private Boolean planRoadDirection = null;
|
private Boolean planRoadDirection = null;
|
||||||
private VehicleRouter router = new CarRouter();
|
private VehicleRouter router = new CarRouter();
|
||||||
|
@ -29,13 +33,10 @@ public class RoutingContext {
|
||||||
// not used right now
|
// not used right now
|
||||||
private boolean usingShortestWay = false;
|
private boolean usingShortestWay = false;
|
||||||
|
|
||||||
|
|
||||||
// 2. Routing memory cache (big objects)
|
// 2. Routing memory cache (big objects)
|
||||||
TLongObjectMap<RouteSegment> routes = new TLongObjectHashMap<RouteSegment>();
|
TIntObjectHashMap<RoutingTile> tiles = new TIntObjectHashMap<RoutingContext.RoutingTile>();
|
||||||
TIntSet loadedTiles = new TIntHashSet();
|
|
||||||
// TODO delete this object ?
|
int garbageCollectorIteration = 0;
|
||||||
TLongObjectHashMap<RouteDataObject> idObjects = new TLongObjectHashMap<RouteDataObject>();
|
|
||||||
int relaxedIteration = 0;
|
|
||||||
|
|
||||||
// 4. Warm object caches
|
// 4. Warm object caches
|
||||||
TLongSet nonRestrictedIds = new TLongHashSet();
|
TLongSet nonRestrictedIds = new TLongHashSet();
|
||||||
|
@ -57,22 +58,32 @@ public class RoutingContext {
|
||||||
// 3. debug information (package accessor)
|
// 3. debug information (package accessor)
|
||||||
long timeToLoad = 0;
|
long timeToLoad = 0;
|
||||||
long timeToCalculate = 0;
|
long timeToCalculate = 0;
|
||||||
|
int loadedTiles = 0;
|
||||||
|
int maxLoadedTiles = 0;
|
||||||
|
int loadedPrevUnloadedTiles = 0;
|
||||||
|
int unloadedTiles = 0;
|
||||||
|
TIntHashSet distinctUnloadedTiles = new TIntHashSet();
|
||||||
int visitedSegments = 0;
|
int visitedSegments = 0;
|
||||||
int relaxedSegments = 0;
|
int relaxedSegments = 0;
|
||||||
// callback of processing segments
|
// callback of processing segments
|
||||||
RouteSegmentVisitor visitor = null;
|
RouteSegmentVisitor visitor = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public RouteSegmentVisitor getVisitor() {
|
public RouteSegmentVisitor getVisitor() {
|
||||||
return visitor;
|
return visitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TLongObjectMap<RouteSegment> getLoadedRoutes() {
|
public int getCurrentlyLoadedTiles() {
|
||||||
return routes;
|
int cnt = 0;
|
||||||
|
Iterator<RoutingTile> it = tiles.valueCollection().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
if (it.next().isLoaded()) {
|
||||||
|
cnt++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setVisitor(RouteSegmentVisitor visitor) {
|
public void setVisitor(RouteSegmentVisitor visitor) {
|
||||||
this.visitor = visitor;
|
this.visitor = visitor;
|
||||||
|
@ -86,6 +97,14 @@ public class RoutingContext {
|
||||||
return zoomToLoadTileWithRoads;
|
return zoomToLoadTileWithRoads;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUseRelaxingStrategy() {
|
||||||
|
return useRelaxingStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseRelaxingStrategy(boolean useRelaxingStrategy) {
|
||||||
|
this.useRelaxingStrategy = useRelaxingStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
public void setUseDynamicRoadPrioritising(boolean useDynamicRoadPrioritising) {
|
public void setUseDynamicRoadPrioritising(boolean useDynamicRoadPrioritising) {
|
||||||
this.useDynamicRoadPrioritising = useDynamicRoadPrioritising;
|
this.useDynamicRoadPrioritising = useDynamicRoadPrioritising;
|
||||||
}
|
}
|
||||||
|
@ -98,11 +117,12 @@ public class RoutingContext {
|
||||||
return usingShortestWay;
|
return usingShortestWay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setRouter(VehicleRouter router) {
|
public void setRouter(VehicleRouter router) {
|
||||||
this.router = router;
|
this.router = router;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeuristicCoefficient(int heuristicCoefficient) {
|
public void setHeuristicCoefficient(double heuristicCoefficient) {
|
||||||
this.heuristicCoefficient = heuristicCoefficient;
|
this.heuristicCoefficient = heuristicCoefficient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,4 +146,79 @@ public class RoutingContext {
|
||||||
return BinaryRoutePlanner.roadPriorityComparator(o1DistanceFromStart, o1DistanceToEnd, o2DistanceFromStart, o2DistanceToEnd,
|
return BinaryRoutePlanner.roadPriorityComparator(o1DistanceFromStart, o1DistanceToEnd, o2DistanceFromStart, o2DistanceToEnd,
|
||||||
heuristicCoefficient);
|
heuristicCoefficient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RoutingTile getRoutingTile(int x31, int y31){
|
||||||
|
int xloc = x31 >> (31 - zoomToLoadTileWithRoads);
|
||||||
|
int yloc = y31 >> (31 - zoomToLoadTileWithRoads);
|
||||||
|
int l = (xloc << zoomToLoadTileWithRoads) + yloc;
|
||||||
|
RoutingTile tl = tiles.get(l);
|
||||||
|
if(tl == null) {
|
||||||
|
tl = new RoutingTile(xloc, yloc, zoomToLoadTileWithRoads);
|
||||||
|
tiles.put(l, tl);
|
||||||
|
}
|
||||||
|
return tiles.get(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unloadTile(RoutingTile tile, boolean createEmpty){
|
||||||
|
int l = (tile.tileX << zoomToLoadTileWithRoads) + tile.tileY;
|
||||||
|
RoutingTile old = tiles.remove(l);
|
||||||
|
RoutingTile n = new RoutingTile(tile.tileX, tile.tileY, zoomToLoadTileWithRoads);
|
||||||
|
n.isLoaded = old.isLoaded;
|
||||||
|
n.setUnloaded();
|
||||||
|
tiles.put(l, n);
|
||||||
|
unloadedTiles++;
|
||||||
|
distinctUnloadedTiles.add(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RoutingTile {
|
||||||
|
private int tileX;
|
||||||
|
private int tileY;
|
||||||
|
private int zoom;
|
||||||
|
private int isLoaded;
|
||||||
|
// make it without get/set for fast access
|
||||||
|
public int access;
|
||||||
|
|
||||||
|
public RoutingTile(int tileX, int tileY, int zoom) {
|
||||||
|
this.tileX = tileX;
|
||||||
|
this.tileY = tileY;
|
||||||
|
this.zoom = zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoaded() {
|
||||||
|
return isLoaded > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUnloadCont(){
|
||||||
|
return Math.abs(isLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUnloaded() {
|
||||||
|
return isLoaded < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnloaded() {
|
||||||
|
if(isLoaded == 0) {
|
||||||
|
this.isLoaded = -1;
|
||||||
|
} else {
|
||||||
|
isLoaded = -Math.abs(isLoaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoaded() {
|
||||||
|
isLoaded = Math.abs(isLoaded) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TLongObjectMap<RouteSegment> routes = new TLongObjectHashMap<RouteSegment>();
|
||||||
|
TIntSet loadedTiles = new TIntHashSet();
|
||||||
|
// TODO delete this object ?
|
||||||
|
TLongObjectHashMap<RouteDataObject> idObjects = new TLongObjectHashMap<RouteDataObject>();
|
||||||
|
|
||||||
|
public boolean checkContains(int x31, int y31) {
|
||||||
|
return tileX == (x31 >> (31 - zoom)) && tileY == (y31 >> (31 - zoom));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TLongObjectMap<RouteSegment> getLoadedRoutes() {
|
||||||
|
return routes;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -214,7 +214,8 @@ public class MapClusterLayer implements MapPanelLayer {
|
||||||
RouteDataObject startRoad = st.getRoad();
|
RouteDataObject startRoad = st.getRoad();
|
||||||
long lstart = (((long) startRoad.getPoint31XTile(st.getSegmentStart())) << 31) +
|
long lstart = (((long) startRoad.getPoint31XTile(st.getSegmentStart())) << 31) +
|
||||||
(long) startRoad.getPoint31YTile(st.getSegmentStart());
|
(long) startRoad.getPoint31YTile(st.getSegmentStart());
|
||||||
RouteSegment next = ctx.getLoadedRoutes().get(lstart);
|
RouteSegment next = ctx.getRoutingTile((int)lstart>>31, (int) (lstart- (lstart>>31)<<31)).
|
||||||
|
getLoadedRoutes().get(lstart);
|
||||||
while (next != null) {
|
while (next != null) {
|
||||||
if(next.getRoad().getId() != st.getRoad().getId()){
|
if(next.getRoad().getId() != st.getRoad().getId()){
|
||||||
queue.add(next);
|
queue.add(next);
|
||||||
|
@ -283,7 +284,7 @@ public class MapClusterLayer implements MapPanelLayer {
|
||||||
|
|
||||||
router.loadRoutes(ctx, x ,y , null);
|
router.loadRoutes(ctx, x ,y , null);
|
||||||
long l = (((long) x) << 31) + (long) y;
|
long l = (((long) x) << 31) + (long) y;
|
||||||
next = ctx.getLoadedRoutes().get(l);
|
next = ctx.getRoutingTile(x, y).getLoadedRoutes().get(l);
|
||||||
boolean addToQueue = true;;
|
boolean addToQueue = true;;
|
||||||
while (next != null) {
|
while (next != null) {
|
||||||
String h = getHighway(next.getRoad());
|
String h = getHighway(next.getRoad());
|
||||||
|
@ -300,7 +301,7 @@ public class MapClusterLayer implements MapPanelLayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addToQueue) {
|
if (addToQueue) {
|
||||||
next = ctx.getLoadedRoutes().get(l);
|
next = ctx.getRoutingTile(x, y).getLoadedRoutes().get(l);
|
||||||
while (next != null) {
|
while (next != null) {
|
||||||
if (!visitedIds.contains(calculateId(next, next.getSegmentStart()))) {
|
if (!visitedIds.contains(calculateId(next, next.getSegmentStart()))) {
|
||||||
queue.add(next);
|
queue.add(next);
|
||||||
|
|
Loading…
Reference in a new issue