From 1f7f7f54da1b537f5bef97f92e955a8f87a89c63 Mon Sep 17 00:00:00 2001 From: vshcherb Date: Sun, 2 Mar 2014 18:24:02 +0200 Subject: [PATCH] Add osmand route calculation following gpx track --- .../router/PrecalculatedRouteDirection.java | 23 ++ OsmAnd/res/values/strings.xml | 1 + .../osmand/plus/OsmAndLocationSimulation.java | 9 +- .../src/net/osmand/plus/OsmandSettings.java | 1 + .../activities/actions/NavigateAction.java | 21 +- .../osmand/plus/base/FailSafeFuntions.java | 19 +- .../osmand/plus/routing/RouteProvider.java | 225 +++++++++++++----- 7 files changed, 226 insertions(+), 73 deletions(-) diff --git a/OsmAnd-java/src/net/osmand/router/PrecalculatedRouteDirection.java b/OsmAnd-java/src/net/osmand/router/PrecalculatedRouteDirection.java index bdce12e940..68bcc8195e 100644 --- a/OsmAnd-java/src/net/osmand/router/PrecalculatedRouteDirection.java +++ b/OsmAnd-java/src/net/osmand/router/PrecalculatedRouteDirection.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; import net.osmand.binary.RouteDataObject; +import net.osmand.data.LatLon; import net.osmand.data.QuadPoint; import net.osmand.data.QuadRect; import net.osmand.data.QuadTree; @@ -42,6 +43,11 @@ public class PrecalculatedRouteDirection { init(ls); } + private PrecalculatedRouteDirection(LatLon[] ls, float maxSpeed) { + this.maxSpeed = maxSpeed; + init(ls); + } + private PrecalculatedRouteDirection(PrecalculatedRouteDirection parent, int s1, int s2) { this.minSpeed = parent.minSpeed; this.maxSpeed = parent.maxSpeed; @@ -81,6 +87,10 @@ public class PrecalculatedRouteDirection { return null; } + public static PrecalculatedRouteDirection build(LatLon[] ls, float maxSpeed){ + return new PrecalculatedRouteDirection(ls, maxSpeed); + } + private void init(List ls) { TIntArrayList px = new TIntArrayList(); @@ -104,6 +114,19 @@ public class PrecalculatedRouteDirection { } init(px, py, speedSegments); } + + private void init(LatLon[] ls) { + TIntArrayList px = new TIntArrayList(); + TIntArrayList py = new TIntArrayList(); + List speedSegments = new ArrayList(); + for (LatLon s : ls) { + float routeSpd = maxSpeed; // (s.getDistance() / s.getRoutingTime()) + px.add(MapUtils.get31TileNumberX(s.getLongitude())); + py.add(MapUtils.get31TileNumberY(s.getLatitude())); + speedSegments.add(routeSpd); + } + init(px, py, speedSegments); + } private void init(TIntArrayList px, TIntArrayList py, List speedSegments) { float totaltm = 0; diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 06c3bab9c0..b686fc5d54 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -9,6 +9,7 @@ 3. All your modified/created strings are in the top of the file (to make easier find what\'s translated). PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy --> + Calculate OsmAnd offline route Truck Navigation preferences Routing preferences diff --git a/OsmAnd/src/net/osmand/plus/OsmAndLocationSimulation.java b/OsmAnd/src/net/osmand/plus/OsmAndLocationSimulation.java index 9387bdafbc..0c0795c83f 100644 --- a/OsmAnd/src/net/osmand/plus/OsmAndLocationSimulation.java +++ b/OsmAnd/src/net/osmand/plus/OsmAndLocationSimulation.java @@ -8,8 +8,8 @@ import net.osmand.CallbackWithObject; import net.osmand.Location; import net.osmand.access.AccessibleToast; import net.osmand.plus.activities.MapActivity; -import net.osmand.plus.routing.RouteProvider; import net.osmand.plus.routing.RouteProvider.GPXRouteParams; +import net.osmand.plus.routing.RouteProvider.GPXRouteParams.GPXRouteParamsBuilder; import net.osmand.plus.routing.RoutingHelper; import android.app.AlertDialog; import android.app.AlertDialog.Builder; @@ -72,8 +72,11 @@ public class OsmAndLocationSimulation { new CallbackWithObject() { @Override public boolean processResult(GPXUtilities.GPXFile result) { - GPXRouteParams prms = new RouteProvider.GPXRouteParams(result, false, ch - .isChecked(), app.getSettings()); + GPXRouteParamsBuilder builder = GPXRouteParams.GPXRouteParamsBuilder.newBuilder(result, app.getSettings()); + if(ch.isChecked()){ + builder.announceWaypoints(); + } + GPXRouteParams prms = builder.build(); startAnimationThread(app.getRoutingHelper(), ma, prms.getPoints(), true, speedup.getProgress() + 1); return true; diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index 13e3a77263..d7f3161e39 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -739,6 +739,7 @@ public class OsmandSettings { public final OsmandPreference SPEAK_SPEED_LIMIT = new BooleanPreference("speak_speed_limit", true).makeProfile().cache(); public final OsmandPreference SPEAK_GPX_WPT = new BooleanPreference("speak_gpx_wpt", true).makeGlobal().cache(); + public final OsmandPreference CALC_GPX_ROUTE = new BooleanPreference("calc_gpx_route", false).makeGlobal().cache(); diff --git a/OsmAnd/src/net/osmand/plus/activities/actions/NavigateAction.java b/OsmAnd/src/net/osmand/plus/activities/actions/NavigateAction.java index f6712b5f91..a2f401f3e3 100644 --- a/OsmAnd/src/net/osmand/plus/activities/actions/NavigateAction.java +++ b/OsmAnd/src/net/osmand/plus/activities/actions/NavigateAction.java @@ -19,6 +19,7 @@ import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.routing.RouteProvider.GPXRouteParams; import net.osmand.plus.routing.RouteProvider.RouteService; +import net.osmand.plus.routing.RouteProvider.GPXRouteParams.GPXRouteParamsBuilder; import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; @@ -66,10 +67,11 @@ public class NavigateAction { public boolean navigateUsingGPX(final ApplicationMode appMode, final LatLon endForRouting, final GPXFile result) { Builder builder = new AlertDialog.Builder(mapActivity); - final boolean[] props = new boolean[]{false, false, false, settings.SPEAK_GPX_WPT.get()}; + final boolean[] props = new boolean[]{false, false, false, settings.SPEAK_GPX_WPT.get(), settings.CALC_GPX_ROUTE.get()}; builder.setMultiChoiceItems(new String[] { getString(R.string.gpx_option_reverse_route), getString(R.string.gpx_option_destination_point), getString(R.string.gpx_option_from_start_point), - getString(R.string.announce_gpx_waypoints) }, props, + getString(R.string.announce_gpx_waypoints), + getString(R.string.calculate_osmand_route_gpx)}, props, new OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { @@ -83,9 +85,20 @@ public class NavigateAction { boolean passWholeWay = props[2]; boolean useDestination = props[1]; boolean announceGpxWpt = props[3]; + boolean calculateOsmAndRoute = props[4]; settings.SPEAK_GPX_WPT.set(announceGpxWpt); - GPXRouteParams gpxRoute = new GPXRouteParams(result, reverse, announceGpxWpt, settings); - + settings.CALC_GPX_ROUTE.set(calculateOsmAndRoute); + GPXRouteParamsBuilder bld = GPXRouteParamsBuilder.newBuilder(result, settings); + if(reverse) { + bld.reverse(); + } + if(announceGpxWpt) { + bld.announceWaypoints(); + } + if(calculateOsmAndRoute) { + bld.calculateOsmAndRoute(); + } + GPXRouteParams gpxRoute = bld.build(); Location loc = getLastKnownLocation(); if(passWholeWay && loc != null){ gpxRoute.setStartPoint(loc); diff --git a/OsmAnd/src/net/osmand/plus/base/FailSafeFuntions.java b/OsmAnd/src/net/osmand/plus/base/FailSafeFuntions.java index 0ed3c6d6cd..e66a6781d3 100644 --- a/OsmAnd/src/net/osmand/plus/base/FailSafeFuntions.java +++ b/OsmAnd/src/net/osmand/plus/base/FailSafeFuntions.java @@ -16,6 +16,7 @@ import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.routing.RouteProvider.GPXRouteParams; +import net.osmand.plus.routing.RouteProvider.GPXRouteParams.GPXRouteParamsBuilder; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.DialogInterface; @@ -123,14 +124,26 @@ public class FailSafeFuntions { @Override protected void onPostExecute(GPXFile result) { - final GPXRouteParams gpxRoute = result == null ? null : new GPXRouteParams(result, false, - settings.SPEAK_GPX_WPT.get(), settings); + final GPXRouteParams gpxRoute; + if (result != null) { + GPXRouteParamsBuilder builder = GPXRouteParamsBuilder.newBuilder(result, settings); + if (settings.SPEAK_GPX_WPT.get()) { + builder.announceWaypoints(); + } + if(settings.CALC_GPX_ROUTE.get()) { + builder.calculateOsmAndRoute(); + } + gpxRoute = builder.build(); + } else { + gpxRoute = null; + } LatLon endPoint = pointToNavigate != null ? pointToNavigate : gpxRoute.getLastPoint(); net.osmand.Location startPoint = gpxRoute == null ? null : gpxRoute.getStartPointForRoute(); if (endPoint == null) { notRestoreRoutingMode(ma, app); } else { - ma.followRoute(settings.getApplicationMode(), endPoint, targetPoints.getIntermediatePoints(), startPoint, gpxRoute); + ma.followRoute(settings.getApplicationMode(), endPoint, + targetPoints.getIntermediatePoints(), startPoint, gpxRoute); } } }; diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java index 6e9073435c..e8cbf61d0e 100644 --- a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java +++ b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java @@ -3,6 +3,7 @@ package net.osmand.plus.routing; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.StringReader; @@ -48,6 +49,7 @@ import net.osmand.router.GeneralRouter; import net.osmand.router.GeneralRouter.GeneralRouterProfile; import net.osmand.router.GeneralRouter.RoutingParameter; import net.osmand.router.GeneralRouter.RoutingParameterType; +import net.osmand.router.PrecalculatedRouteDirection; import net.osmand.router.RoutePlannerFrontEnd; import net.osmand.router.RoutePlannerFrontEnd.RouteCalculationMode; import net.osmand.router.RouteSegmentResult; @@ -115,9 +117,9 @@ public class RouteProvider { List points = new ArrayList(); List directions; DataTileManager wpt; + boolean calculateOsmAndRoute = false; - public GPXRouteParams(GPXFile file, boolean reverse, boolean announceWaypoints, OsmandSettings settings){ - prepareEverything(file, reverse, announceWaypoints, settings.DRIVING_REGION.get().leftHandDriving); + private GPXRouteParams(){ } public void setStartPoint(Location startPoint) { @@ -144,6 +146,45 @@ public class RouteProvider { return null; } + public static class GPXRouteParamsBuilder { + + private GPXRouteParams obj = new GPXRouteParams(); + private GPXFile file; + private boolean leftHandDriving; + private boolean reverse; + private boolean announceWaypoints; + private GPXRouteParamsBuilder(GPXFile f, OsmandSettings settings) { + this.file = f; + leftHandDriving = settings.DRIVING_REGION.get().leftHandDriving; +// obj = new GPXRouteParams(file, reverse, announceWaypoints, settings) + // TODO Auto-generated constructor stub + } + + public GPXRouteParamsBuilder reverse() { + this.reverse = true; + return this; + } + + public GPXRouteParamsBuilder announceWaypoints() { + this.announceWaypoints = true; + return this; + } + + public GPXRouteParamsBuilder calculateOsmAndRoute() { + obj.calculateOsmAndRoute = true; + return this; + } + + public static GPXRouteParamsBuilder newBuilder(GPXFile f, OsmandSettings settings) { + return new GPXRouteParamsBuilder(f, settings); + } + + public GPXRouteParams build(){ + obj.prepareEverything(file, reverse, announceWaypoints, leftHandDriving); + return obj; + } + } + private void prepareEverything(GPXFile file, boolean reverse, boolean announceWaypoints, boolean leftSide){ if(file.isCloudmadeRouteFile() || OSMAND_ROUTER.equals(file.author)){ directions = parseCloudmadeRoute(points, file, OSMAND_ROUTER.equals(file.author), leftSide, 10); @@ -210,7 +251,10 @@ public class RouteProvider { } try { RouteCalculationResult res; - if(params.gpxRoute != null && !params.gpxRoute.points.isEmpty()){ + boolean calcGPXRoute = params.gpxRoute != null && !params.gpxRoute.points.isEmpty(); + if (params.type == RouteService.OSMAND || (calcGPXRoute && params.gpxRoute.calculateOsmAndRoute)) { + res = findVectorMapsRoute(params, calcGPXRoute); + } else if(calcGPXRoute){ res = calculateGpxRoute(params); } else if (params.type == RouteService.YOURS) { res = findYOURSRoute(params); @@ -218,8 +262,6 @@ public class RouteProvider { res = findORSRoute(params); } else if (params.type == RouteService.OSRM) { res = findOSRMRoute(params); - } else if (params.type == RouteService.OSMAND) { - res = findVectorMapsRoute(params); } else if (params.type == RouteService.BROUTER) { res = findBROUTERRoute(params); } else { @@ -246,45 +288,20 @@ public class RouteProvider { private RouteCalculationResult calculateGpxRoute(RouteCalculationParams pars) { RouteCalculationResult res; // get the closest point to start and to end - float minDist = Integer.MAX_VALUE; - int startI = 0; GPXRouteParams params = pars.gpxRoute; List gpxRoute = params.points; - int endI = gpxRoute.size(); - if (pars.start != null) { - for (int i = 0; i < gpxRoute.size(); i++) { - float d = gpxRoute.get(i).distanceTo(pars.start); - if (d < minDist) { - startI = i; - minDist = d; - } - } - } else { - pars.start = gpxRoute.get(0); - } - Location l = new Location("temp"); //$NON-NLS-1$ - l.setLatitude(pars.end.getLatitude()); - l.setLongitude(pars.end.getLongitude()); - minDist = Integer.MAX_VALUE; - // get in reverse order taking into account ways with cycle - for (int i = gpxRoute.size() - 1; i >= startI; i--) { - float d = gpxRoute.get(i).distanceTo(l); - if (d < minDist) { - endI = i + 1; - // slightly modify to allow last point to be added - minDist = d - 40; - } - } - ArrayList sublist = new ArrayList(gpxRoute.subList(startI, endI)); + int[] startI = new int[]{0}; + int[] endI = new int[]{gpxRoute.size()}; + ArrayList sublist = findGpxLocations(pars, startI, endI); pars.intermediates = null; if(params.directions == null){ res = new RouteCalculationResult(sublist, null, pars, params.wpt); } else { List subdirections = new ArrayList(); for (RouteDirectionInfo info : params.directions) { - if(info.routePointOffset >= startI && info.routePointOffset < endI){ + if(info.routePointOffset >= startI[0] && info.routePointOffset < endI[0]){ RouteDirectionInfo ch = new RouteDirectionInfo(info.getAverageSpeed(), info.getTurnType()); - ch.routePointOffset = info.routePointOffset - startI; + ch.routePointOffset = info.routePointOffset - startI[0]; ch.setDescriptionRoute(info.getDescriptionRoute()); // recalculate @@ -297,6 +314,49 @@ public class RouteProvider { } return res; } + + + + + private ArrayList findGpxLocations(RouteCalculationParams pars, int[] startI, int[] endI) { + GPXRouteParams params = pars.gpxRoute; + List gpxRoute = params.points; + float minDist = Integer.MAX_VALUE; + int start = 0; + int end = gpxRoute.size(); + if (pars.start != null) { + for (int i = 0; i < gpxRoute.size(); i++) { + float d = gpxRoute.get(i).distanceTo(pars.start); + if (d < minDist) { + start = i; + minDist = d; + } + } + } else { + pars.start = gpxRoute.get(0); + } + Location l = new Location("temp"); //$NON-NLS-1$ + l.setLatitude(pars.end.getLatitude()); + l.setLongitude(pars.end.getLongitude()); + minDist = Integer.MAX_VALUE; + // get in reverse order taking into account ways with cycle + for (int i = gpxRoute.size() - 1; i >= start; i--) { + float d = gpxRoute.get(i).distanceTo(l); + if (d < minDist) { + end = i + 1; + // slightly modify to allow last point to be added + minDist = d - 40; + } + } + ArrayList sublist = new ArrayList(gpxRoute.subList(start, end)); + if(startI != null) { + startI[0] = start; + } + if(endI != null) { + endI[0] = end; + } + return sublist; + } protected String getString(ClientContext ctx, int resId){ if(ctx == null){ @@ -370,10 +430,65 @@ public class RouteProvider { return new RouteCalculationResult(res, null, params, null); } - protected RouteCalculationResult findVectorMapsRoute(final RouteCalculationParams params) throws IOException { + protected RouteCalculationResult findVectorMapsRoute(final RouteCalculationParams params, boolean calcGPXRoute) throws IOException { BinaryMapIndexReader[] files = params.ctx.getTodoAPI().getRoutingMapFiles(); RoutePlannerFrontEnd router = new RoutePlannerFrontEnd(false); OsmandSettings settings = params.ctx.getSettings(); + + GeneralRouter generalRouter = SettingsNavigationActivity.getRouter(params.mode); + if(generalRouter == null) { + return applicationModeNotSupported(params); + } + RoutingConfiguration cf = initOsmAndRoutingConfig(params, settings, generalRouter); + if(cf == null){ + return applicationModeNotSupported(params); + } + PrecalculatedRouteDirection precalculated = null; + if(calcGPXRoute) { + ArrayList sublist = findGpxLocations(params, null, null); + LatLon[] latLon = new LatLon[sublist.size()]; + for(int k = 0; k < latLon.length; k ++) { + latLon[k] = new LatLon(sublist.get(k).getLatitude(), sublist.get(k).getLongitude()); + } + precalculated = PrecalculatedRouteDirection.build(latLon, generalRouter.getMaxDefaultSpeed()); + cf.planRoadDirection = 1; + } + // BUILD context + RoutingContext ctx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files, + RouteCalculationMode.NORMAL); + + RoutingContext complexCtx = null; + boolean complex = params.mode.isDerivedRoutingFrom(ApplicationMode.CAR) && !settings.DISABLE_COMPLEX_ROUTING.get() + && precalculated == null; + if(complex) { + complexCtx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files, + RouteCalculationMode.COMPLEX); + complexCtx.calculationProgress = params.calculationProgress; + complexCtx.leftSideNavigation = params.leftSide; + } + if(precalculated != null) { + ctx.precalculatedRouteDirection = precalculated.adopt(ctx); + } + ctx.leftSideNavigation = params.leftSide; + ctx.calculationProgress = params.calculationProgress; + if(params.previousToRecalculate != null) { + // not used any more + // ctx.previouslyCalculatedRoute = params.previousToRecalculate.getOriginalRoute(); + } + LatLon st = new LatLon(params.start.getLatitude(), params.start.getLongitude()); + LatLon en = new LatLon(params.end.getLatitude(), params.end.getLongitude()); + List inters = new ArrayList(); + if (params.intermediates != null) { + inters = new ArrayList(params.intermediates); + } + return calcOfflineRouteImpl(params, router, ctx, complexCtx, st, en, inters); + } + + + + + private RoutingConfiguration initOsmAndRoutingConfig(final RouteCalculationParams params, OsmandSettings settings, + GeneralRouter generalRouter) throws IOException, FileNotFoundException { File routingXml = params.ctx.getAppPath(IndexConstants.ROUTING_XML_FILE); RoutingConfiguration.Builder config ; if (routingXml.exists() && routingXml.canRead()) { @@ -393,12 +508,9 @@ public class RouteProvider { } else if(params.mode.isDerivedRoutingFrom(ApplicationMode.CAR)){ p = GeneralRouterProfile.CAR; } else { - return applicationModeNotSupported(params); - } - GeneralRouter generalRouter = SettingsNavigationActivity.getRouter(params.mode); - if(generalRouter == null) { - return applicationModeNotSupported(params); + return null; } + Map paramsR = new LinkedHashMap(); for(Map.Entry e : generalRouter.getParameters().entrySet()){ String key = e.getKey(); @@ -427,28 +539,15 @@ public class RouteProvider { RoutingConfiguration cf = config.build(p.name().toLowerCase(), params.start.hasBearing() ? params.start.getBearing() / 180d * Math.PI : null, memoryLimit, paramsR); - boolean complex = params.mode.isDerivedRoutingFrom(ApplicationMode.CAR) && !settings.DISABLE_COMPLEX_ROUTING.get(); - RoutingContext ctx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files, - RouteCalculationMode.NORMAL); - RoutingContext complexCtx = null; - if(complex) { - complexCtx = router.buildRoutingContext(cf, params.ctx.getInternalAPI().getNativeLibrary(), files, - RouteCalculationMode.COMPLEX); - complexCtx.calculationProgress = params.calculationProgress; - complexCtx.leftSideNavigation = params.leftSide; - } - ctx.leftSideNavigation = params.leftSide; - ctx.calculationProgress = params.calculationProgress; - if(params.previousToRecalculate != null) { - // not used any more - // ctx.previouslyCalculatedRoute = params.previousToRecalculate.getOriginalRoute(); - } - LatLon st = new LatLon(params.start.getLatitude(), params.start.getLongitude()); - LatLon en = new LatLon(params.end.getLatitude(), params.end.getLongitude()); - List inters = new ArrayList(); - if (params.intermediates != null) { - inters = new ArrayList(params.intermediates); - } + return cf; + } + + + + + private RouteCalculationResult calcOfflineRouteImpl(final RouteCalculationParams params, + RoutePlannerFrontEnd router, RoutingContext ctx, RoutingContext complexCtx, LatLon st, LatLon en, + List inters) throws IOException { try { List result ; if(complexCtx != null) {