New change for fast route recalculation

This commit is contained in:
Victor Shcherb 2015-04-30 00:47:57 +02:00
parent a6342996e3
commit 0055c3edd0
9 changed files with 123 additions and 24 deletions

View file

@ -4,6 +4,7 @@ import gnu.trove.map.hash.TLongObjectHashMap;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@ -65,12 +66,15 @@ public class BinaryRoutePlanner {
* return list of segments
*/
@SuppressWarnings("unused")
FinalRouteSegment searchRouteInternal(final RoutingContext ctx, RouteSegmentPoint start, RouteSegmentPoint end) throws InterruptedException, IOException {
FinalRouteSegment searchRouteInternal(final RoutingContext ctx, RouteSegmentPoint start, RouteSegmentPoint end,
RouteSegment recalculationEnd ) throws InterruptedException, IOException {
// measure time
ctx.timeToLoad = 0;
ctx.visitedSegments = 0;
ctx.memoryOverhead = 1000;
ctx.timeToCalculate = System.nanoTime();
// Initializing priority queue to visit way segments
Comparator<RouteSegment> nonHeuristicSegmentsComparator = new NonHeuristicSegmentsComparator();
PriorityQueue<RouteSegment> graphDirectSegments = new PriorityQueue<RouteSegment>(50, new SegmentsComparator(ctx));
@ -80,8 +84,7 @@ public class BinaryRoutePlanner {
TLongObjectHashMap<RouteSegment> visitedDirectSegments = new TLongObjectHashMap<RouteSegment>();
TLongObjectHashMap<RouteSegment> visitedOppositeSegments = new TLongObjectHashMap<RouteSegment>();
initQueuesWithStartEnd(ctx, start, end, graphDirectSegments, graphReverseSegments);
initQueuesWithStartEnd(ctx, start, end, recalculationEnd, graphDirectSegments, graphReverseSegments);
// Extract & analyze segment with min(f(x)) from queue while final segment is not found
boolean forwardSearch = true;
@ -90,7 +93,7 @@ public class BinaryRoutePlanner {
FinalRouteSegment finalSegment = null;
boolean onlyBackward = ctx.getPlanRoadDirection() < 0;
boolean onlyForward = ctx.getPlanRoadDirection() > 0;
boolean onlyForward = ctx.getPlanRoadDirection() > 0 ;
while (!graphSegments.isEmpty()) {
RouteSegment segment = graphSegments.poll();
// use accumulative approach
@ -169,6 +172,9 @@ public class BinaryRoutePlanner {
}
protected void checkIfGraphIsEmpty(final RoutingContext ctx, boolean allowDirection,
PriorityQueue<RouteSegment> graphSegments, RouteSegmentPoint pnt, TLongObjectHashMap<RouteSegment> visited,
String msg) {
@ -238,7 +244,7 @@ public class BinaryRoutePlanner {
private void initQueuesWithStartEnd(final RoutingContext ctx, RouteSegment start, RouteSegment end,
PriorityQueue<RouteSegment> graphDirectSegments, PriorityQueue<RouteSegment> graphReverseSegments) {
RouteSegment recalculationEnd, PriorityQueue<RouteSegment> graphDirectSegments, PriorityQueue<RouteSegment> graphReverseSegments) {
RouteSegment startPos = initRouteSegment(ctx, start, true);
RouteSegment startNeg = initRouteSegment(ctx, start, false);
RouteSegment endPos = initRouteSegment(ctx, end, true);
@ -258,6 +264,10 @@ public class BinaryRoutePlanner {
}
}
}
if(recalculationEnd != null) {
ctx.targetX = recalculationEnd.getRoad().getPoint31XTile(recalculationEnd.getSegmentStart());
ctx.targetY = recalculationEnd.getRoad().getPoint31YTile(recalculationEnd.getSegmentStart());
}
float estimatedDistance = (float) estimatedDistance(ctx, ctx.targetX, ctx.targetY, ctx.startX, ctx.startY);
if(startPos != null) {
startPos.distanceToEnd = estimatedDistance;
@ -267,13 +277,17 @@ public class BinaryRoutePlanner {
startNeg.distanceToEnd = estimatedDistance;
graphDirectSegments.add(startNeg);
}
if(endPos != null) {
endPos.distanceToEnd = estimatedDistance;
graphReverseSegments.add(endPos);
}
if(endNeg != null) {
endNeg.distanceToEnd = estimatedDistance;
graphReverseSegments.add(endNeg);
if(recalculationEnd != null) {
graphReverseSegments.add(recalculationEnd);
} else {
if (endPos != null) {
endPos.distanceToEnd = estimatedDistance;
graphReverseSegments.add(endPos);
}
if (endNeg != null) {
endNeg.distanceToEnd = estimatedDistance;
graphReverseSegments.add(endNeg);
}
}
}

View file

@ -16,6 +16,7 @@ import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
import net.osmand.binary.RouteDataObject;
import net.osmand.data.LatLon;
import net.osmand.data.QuadPoint;
import net.osmand.router.BinaryRoutePlanner.RouteSegment;
import net.osmand.router.BinaryRoutePlanner.RouteSegmentPoint;
import net.osmand.util.MapUtils;
@ -25,6 +26,7 @@ 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;
@ -99,6 +101,10 @@ public class RoutePlannerFrontEnd {
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, LatLon start, LatLon end, List<LatLon> intermediates) throws IOException, InterruptedException {
return searchRoute(ctx, start, end, intermediates, null);
}
public void setUseFastRecalculation(boolean use) {
useSmartRouteRecalculation = use;
}
public List<RouteSegmentResult> searchRoute(final RoutingContext ctx, LatLon start, LatLon end, List<LatLon> intermediates,
@ -127,10 +133,14 @@ public class RoutePlannerFrontEnd {
ctx.startY = MapUtils.get31TileNumberY(start.getLatitude());
ctx.targetX = MapUtils.get31TileNumberX(end.getLongitude());
ctx.targetY = MapUtils.get31TileNumberY(end.getLatitude());
RouteSegment recalculationEnd = getRecalculationEnd(ctx);
if(recalculationEnd != null) {
ctx.initTargetPoint(recalculationEnd);
}
if(routeDirection != null) {
ctx.precalculatedRouteDirection = routeDirection.adopt(ctx);
}
List<RouteSegmentResult> res = runNativeRouting(ctx);
}
List<RouteSegmentResult> res = runNativeRouting(ctx, recalculationEnd);
if(res != null) {
new RouteResultPreparation().printResults(ctx, start, end, res);
}
@ -283,24 +293,62 @@ public class RoutePlannerFrontEnd {
private List<RouteSegmentResult> searchRouteInternalPrepare(final RoutingContext ctx, RouteSegmentPoint start, RouteSegmentPoint end,
PrecalculatedRouteDirection routeDirection) throws IOException, InterruptedException {
ctx.initStartAndTargetPoints(start, end);
RouteSegment recalculationEnd = getRecalculationEnd(ctx);
if(recalculationEnd != null) {
ctx.initStartAndTargetPoints(start, recalculationEnd);
} else {
ctx.initStartAndTargetPoints(start, end);
}
if(routeDirection != null) {
ctx.precalculatedRouteDirection = routeDirection.adopt(ctx);
}
if (ctx.nativeLib != null) {
return runNativeRouting(ctx);
return runNativeRouting(ctx, recalculationEnd);
} 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);
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);
}
}
private RouteSegment getRecalculationEnd(final RoutingContext ctx) {
RouteSegment recalculationEnd = null;
boolean runRecalculation = ctx.previouslyCalculatedRoute != null && ctx.previouslyCalculatedRoute.size() > 0
&& ctx.config.recalculateDistance != 0;
if (runRecalculation) {
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) {
RouteSegment previous = null;
for (int i = 0; i < rlist.size() - 1; i++) {
RouteSegmentResult rr = rlist.get(i);
RouteSegment segment = new RouteSegment(rr.getObject(), rr.getEndPointIndex());
if (previous != null) {
previous.setParentRoute(segment);
previous.setParentSegmentEnd(rr.getStartPointIndex());
} else {
recalculationEnd = segment;
}
previous = segment;
}
}
}
return recalculationEnd;
}
private void refreshProgressDistance(RoutingContext ctx) {
@ -316,16 +364,26 @@ public class RoutePlannerFrontEnd {
}
private List<RouteSegmentResult> runNativeRouting(final RoutingContext ctx) throws IOException {
private List<RouteSegmentResult> runNativeRouting(final RoutingContext ctx, RouteSegment recalculationEnd) throws IOException {
refreshProgressDistance(ctx);
RouteRegion[] regions = ctx.reverseMap.keySet().toArray(new BinaryMapRouteReaderAdapter.RouteRegion[ctx.reverseMap.size()]);
ctx.checkOldRoutingFiles(ctx.startX, ctx.startY);
ctx.checkOldRoutingFiles(ctx.targetX, ctx.targetY);
long time = System.currentTimeMillis();
RouteSegmentResult[] res = ctx.nativeLib.runNativeRouting(ctx.startX, ctx.startY, ctx.targetX, ctx.targetY,
ctx.config, regions, ctx.calculationProgress, ctx.precalculatedRouteDirection, ctx.calculationMode == RouteCalculationMode.BASE);
log.info("Native routing took " + (System.currentTimeMillis() - time) / 1000f + " seconds");
ArrayList<RouteSegmentResult> result = new ArrayList<RouteSegmentResult>(Arrays.asList(res));
if(recalculationEnd != null) {
log.info("Native routing use precalculated route");
RouteSegment current = recalculationEnd;
while(current.getParentRoute() != null) {
RouteSegment pr = current.getParentRoute();
result.add(new RouteSegmentResult(pr.getRoad(), current.getParentSegmentEnd(), pr.getSegmentStart()));
current = pr;
}
}
ctx.routingTime = ctx.calculationProgress.routingCalculatedTime;
ctx.visitedSegments = ctx.calculationProgress.visitedSegments;
ctx.loadedTiles = ctx.calculationProgress.loadedTiles;
@ -336,7 +394,9 @@ public class RoutePlannerFrontEnd {
private List<RouteSegmentResult> searchRoute(final RoutingContext ctx, List<RouteSegmentPoint> points, PrecalculatedRouteDirection routeDirection)
throws IOException, InterruptedException {
if (points.size() <= 2) {
ctx.previouslyCalculatedRoute = null;
if(!useSmartRouteRecalculation) {
ctx.previouslyCalculatedRoute = null;
}
return searchRoute(ctx, points.get(0), points.get(1), routeDirection);
}
@ -372,7 +432,9 @@ public class RoutePlannerFrontEnd {
for (int i = 0; i < points.size() - 1; i++) {
RoutingContext local = new RoutingContext(ctx);
if (i == 0) {
//local.previouslyCalculatedRoute = firstPartRecalculatedRoute;
if (useSmartRouteRecalculation) {
local.previouslyCalculatedRoute = firstPartRecalculatedRoute;
}
}
local.visitor = ctx.visitor;
local.calculationProgress = ctx.calculationProgress;

View file

@ -47,7 +47,7 @@ public class RoutingConfiguration {
public Double initialDirection;
// 1.5 Recalculate distance help
public float recalculateDistance = 10000f;
public float recalculateDistance = 20000f;
public static class Builder {

View file

@ -207,11 +207,15 @@ public class RoutingContext {
}
public void initStartAndTargetPoints(RouteSegment start, RouteSegment end) {
targetX = end.road.getPoint31XTile(end.getSegmentStart());
targetY = end.road.getPoint31YTile(end.getSegmentStart());
initTargetPoint(end);
startX = start.road.getPoint31XTile(start.getSegmentStart());
startY = start.road.getPoint31YTile(start.getSegmentStart());
}
public void initTargetPoint(RouteSegment end) {
targetX = end.road.getPoint31XTile(end.getSegmentStart());
targetY = end.road.getPoint31YTile(end.getSegmentStart());
}
public void unloadAllData() {
unloadAllData(null);

View file

@ -199,6 +199,7 @@ public class MapRendererContext implements RendererRegistry.IRendererLoadedEvent
private void recreateRasterAndSymbolsProvider() {
// Create new map primitiviser
// TODO Victor ask MapPrimitiviser, ObfMapObjectsProvider
MapPrimitiviser mapPrimitiviser = new MapPrimitiviser(mapPresentationEnvironment);
ObfMapObjectsProvider obfMapObjectsProvider = new ObfMapObjectsProvider(obfsCollection);
// Create new map primitives provider

View file

@ -623,7 +623,7 @@ public class OsmandSettings {
registeredPreferences.put(id, p);
return p;
}
public final CommonPreference<Boolean> USE_FAST_RECALCULATION = new BooleanPreference("use_fast_recalculation", true).makeGlobal().cache();
// this value string is synchronized with settings_pref.xml preference name
public final CommonPreference<Boolean> USE_INTERNET_TO_DOWNLOAD_TILES = new BooleanPreference("use_internet_to_download_tiles", true).makeGlobal().cache();

View file

@ -89,6 +89,17 @@ public abstract class SettingsBaseActivity extends ActionBarPreferenceActivity
return p;
}
public CheckBoxPreference createCheckBoxPreference(OsmandPreference<Boolean> b, String title, String summary) {
CheckBoxPreference p = new CheckBoxPreference(this);
p.setTitle(title);
p.setKey(b.getId());
p.setSummary(summary);
p.setOnPreferenceChangeListener(this);
screenPreferences.put(b.getId(), p);
booleanPreferences.put(b.getId(), b);
return p;
}
public CheckBoxPreference createCheckBoxPreference(OsmandPreference<Boolean> b) {
CheckBoxPreference p = new CheckBoxPreference(this);
p.setKey(b.getId());

View file

@ -40,6 +40,9 @@ public class SettingsDevelopmentActivity extends SettingsBaseActivity {
cat.addPreference(dbg);
cat.addPreference(createCheckBoxPreference(settings.DISABLE_COMPLEX_ROUTING, R.string.disable_complex_routing, R.string.disable_complex_routing_descr));
cat.addPreference(createCheckBoxPreference(settings.USE_FAST_RECALCULATION, "Smart route recalculation", "Recalculate only initial part of the route for long trips"));
cat.addPreference(createCheckBoxPreference(settings.USE_MAGNETIC_FIELD_SENSOR_COMPASS, R.string.use_magnetic_sensor, R.string.use_magnetic_sensor_descr));

View file

@ -630,6 +630,7 @@ public class RouteProvider {
BinaryMapIndexReader[] files = params.ctx.getResourceManager().getRoutingMapFiles();
RoutePlannerFrontEnd router = new RoutePlannerFrontEnd(false);
OsmandSettings settings = params.ctx.getSettings();
router.setUseFastRecalculation(settings.USE_FAST_RECALCULATION.get());
RoutingConfiguration.Builder config = params.ctx.getDefaultRoutingConfig();
GeneralRouter generalRouter = SettingsNavigationActivity.getRouter(config, params.mode);
@ -666,6 +667,9 @@ public class RouteProvider {
RouteCalculationMode.COMPLEX);
complexCtx.calculationProgress = params.calculationProgress;
complexCtx.leftSideNavigation = params.leftSide;
if(params.previousToRecalculate != null && params.onlyStartPointChanged) {
complexCtx.previouslyCalculatedRoute = params.previousToRecalculate.getOriginalRoute();
}
}
ctx.leftSideNavigation = params.leftSide;
ctx.calculationProgress = params.calculationProgress;