New change for fast route recalculation
This commit is contained in:
parent
a6342996e3
commit
0055c3edd0
9 changed files with 123 additions and 24 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue