Merge pull request #8439 from osmandapp/straight_to

Direct to work in progress - testing
This commit is contained in:
vshcherb 2020-02-11 19:28:58 +01:00 committed by GitHub
commit fa43de9368
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 208 additions and 17 deletions

View file

@ -661,6 +661,41 @@ public class MapUtils {
return new LatLon(Math.toDegrees(phi2), Math.toDegrees(lambda2));
}
public static double getVectorMagnitude(int startX, int startY, int endX, int endY) {
return Math.sqrt(Math.pow((double) (endX - startX), 2.0) + Math.pow((double) (endY - startY), 2.0));
}
//angle of vector
public static double getAngleForRadiusVector(int startX, int startY, int endX, int endY) {
return 2 * Math.atan((endY - startY) / (endX - startX
+ Math.sqrt(Math.pow((double) (endX - startX), 2.0) + Math.pow((double) (endY - startY), 2.0))));
}
//returns coordinates of point on circle
public static double[] getCoordinatesFromRadiusAndAngle(double centerX, double centerY, double radius, double angle) {
double x = centerX + radius * Math.cos(angle);
double y = centerY + radius * Math.sin(angle);
return new double[]{x,y};
}
//returns signed angle between vectors in radians
public static double getAngleBetweenVectors(int vectorAStartX, int vectorAStartY, int vectorAEndX, int vectorAEndY,
int vectorBStartX, int vectorBStartY, int vectorBEndX, int vectorBEndY) {
int[] vectorA = new int[] {getVectorAxisValue(vectorAStartX, vectorAEndX), getVectorAxisValue(vectorAStartY, vectorAEndY)};
int[] vectorB = new int[] {getVectorAxisValue(vectorBStartX, vectorBEndX), getVectorAxisValue(vectorBStartY, vectorBEndY)};
return Math.atan2(vectorA[0] * vectorB[1] - vectorA[1] * vectorB [0], vectorA[0] * vectorB[0] + vectorA[1] * vectorB[1]);
}
//calculates vector value for axis
public static int getVectorAxisValue(int axisStart, int axisEnd) {
if (axisEnd < axisStart) {
return Math.abs(axisEnd) - Math.abs(axisStart);
} else {
return Math.abs(axisStart) - Math.abs(axisEnd);
}
}
}

View file

@ -11,6 +11,7 @@
Thx - Hardy
-->
<string name="routing_profile_direct_to">Direct-to-point</string>
<string name="clear_recorded_data">Clear recorded data</string>
<string name="release_3_6">
• Profiles: now you can change order, set icon for map, change all setting for base profiles and restore them back to defaults\n\n

View file

@ -20,6 +20,7 @@ public class RoutingProfileDataObject extends ProfileDataObject {
}
public enum RoutingProfilesResources {
DIRECT_TO_MODE(R.string.routing_profile_direct_to, R.drawable.ic_action_navigation_type_direct_to),
STRAIGHT_LINE_MODE(R.string.routing_profile_straightline, R.drawable.ic_action_split_interval),
BROUTER_MODE(R.string.routing_profile_broutrer, R.drawable.ic_action_split_interval),
CAR(R.string.rendering_value_car_name, R.drawable.ic_action_car_dark),

View file

@ -18,7 +18,6 @@ public class RouteCalculationParams {
public LatLon end;
public List<LatLon> intermediates;
public OsmandApplication ctx;
public RoutingContext cachedRoutingContext;
public ApplicationMode mode;
@ -35,6 +34,8 @@ public class RouteCalculationParams {
public RouteCalculationProgressCallback calculationProgressCallback;
public RouteCalculationResultListener resultListener;
public boolean showOriginalRoute;
public interface RouteCalculationResultListener {
void onRouteCalculated(RouteCalculationResult route);
}

View file

@ -64,6 +64,8 @@ public class RouteCalculationResult {
protected int lastWaypointGPX = 0;
protected ApplicationMode appMode;
protected boolean showOriginalRoute = false;
public RouteCalculationResult(String errorMessage) {
this.errorMessage = errorMessage;
this.routingTime = 0;
@ -77,7 +79,7 @@ public class RouteCalculationResult {
this.directions = new ArrayList<RouteDirectionInfo>();
this.alarmInfo = new ArrayList<AlarmInfo>();
}
public RouteCalculationResult(List<Location> list, List<RouteDirectionInfo> directions, RouteCalculationParams params, List<LocationPoint> waypoints, boolean addMissingTurns) {
this.routingTime = 0;
this.loadedTiles = 0;
@ -109,6 +111,8 @@ public class RouteCalculationResult {
calculateIntermediateIndexes(params.ctx, this.locations, params.intermediates, localDirections, this.intermediatePoints);
this.directions = Collections.unmodifiableList(localDirections);
updateDirectionsTime(this.directions, this.listDistance);
this.showOriginalRoute = params.showOriginalRoute;
}
public RouteCalculationResult(List<RouteSegmentResult> list, Location start, LatLon end, List<LatLon> intermediates,
@ -1206,5 +1210,8 @@ public class RouteCalculationResult {
public int imminent;
private int directionInfoInd;
}
public boolean isShowOriginalRoute() {
return showOriginalRoute;
}
}

View file

@ -79,7 +79,8 @@ public class RouteProvider {
public enum RouteService {
OSMAND("OsmAnd (offline)"),
BROUTER("BRouter (offline)"),
STRAIGHT("Straight line");
STRAIGHT("Straight line"),
DIRECT_TO("Direct To");
private final String name;
@ -305,7 +306,7 @@ public class RouteProvider {
try {
RouteCalculationResult res;
boolean calcGPXRoute = params.gpxRoute != null && !params.gpxRoute.points.isEmpty();
if(calcGPXRoute && !params.gpxRoute.calculateOsmAndRoute){
if (calcGPXRoute && !params.gpxRoute.calculateOsmAndRoute) {
res = calculateGpxRoute(params);
} else if (params.mode.getRouteService() == RouteService.OSMAND) {
res = findVectorMapsRoute(params, calcGPXRoute);
@ -315,10 +316,11 @@ public class RouteProvider {
// res = findORSRoute(params);
// } else if (params.type == RouteService.OSRM) {
// res = findOSRMRoute(params);
} else if (params.mode.getRouteService() == RouteService.STRAIGHT){
} else if (params.mode.getRouteService() == RouteService.STRAIGHT) {
res = findStraightRoute(params);
}
else {
} else if (params.mode.getRouteService() == RouteService.DIRECT_TO) {
res = findDirectTo(params);
} else {
res = new RouteCalculationResult("Selected route service is not available");
}
if(log.isInfoEnabled() ){
@ -1257,4 +1259,31 @@ public class RouteProvider {
dots.add(location);
return new RouteCalculationResult(dots, null, params, null, true);
}
private RouteCalculationResult findDirectTo(RouteCalculationParams params) {
params.showOriginalRoute = true;
double[] lats = new double[] { params.start.getLatitude(), params.end.getLatitude() };
double[] lons = new double[] { params.start.getLongitude(), params.end.getLongitude() };
List<LatLon> intermediates = params.intermediates;
List<Location> dots = new ArrayList<Location>();
//writing start location
Location location = new Location(String.valueOf("start"));
location.setLatitude(lats[0]);
location.setLongitude(lons[0]);
//adding intermediate dots if they exists
if (intermediates != null){
for(int i =0; i<intermediates.size();i++){
location = new Location(String.valueOf(i));
location.setLatitude(intermediates.get(i).getLatitude());
location.setLongitude(intermediates.get(i).getLongitude());
dots.add(location);
}
}
//writing end location
location = new Location(String.valueOf("end"));
location.setLatitude(lats[1]);
location.setLongitude(lons[1]);
dots.add(location);
return new RouteCalculationResult(dots, null, params, null, true);
}
}

View file

@ -60,6 +60,9 @@ public class RoutingHelper {
private List<LatLon> intermediatePoints;
private Location lastProjection;
private Location lastFixedLocation;
private Location originalStartingLocation;
private RouteCalculationResult originalRoute = null;
private static final int RECALCULATE_THRESHOLD_COUNT_CAUSING_FULL_RECALCULATE = 3;
private static final int RECALCULATE_THRESHOLD_CAUSING_FULL_RECALCULATE_INTERVAL = 2*60*1000;
@ -176,6 +179,7 @@ public class RoutingHelper {
}
public synchronized void setFinalAndCurrentLocation(LatLon finalLocation, List<LatLon> intermediatePoints, Location currentLocation){
setOriginalStartLocation(currentLocation);
checkAndUpdateStartLocation(currentLocation);
RouteCalculationResult previousRoute = route;
clearCurrentRoute(finalLocation, intermediatePoints);
@ -183,10 +187,30 @@ public class RoutingHelper {
setCurrentLocation(currentLocation, false, previousRoute, true);
}
public RouteCalculationResult getOriginalRoute() {
return originalRoute;
}
public List<Location> getOriginalRouteAllLoc() {
return originalRoute.getImmutableAllLocations();
}
public void setOriginalRoute(RouteCalculationResult originalRoute) {
this.originalRoute = originalRoute;
}
private void setOriginalStartLocation(Location currentLocation) {
originalStartingLocation = currentLocation;
}
public Location getOriginalStartingLocation() {
return originalStartingLocation;
}
public synchronized void clearCurrentRoute(LatLon newFinalLocation, List<LatLon> newIntermediatePoints) {
route = new RouteCalculationResult("");
isDeviatedFromRoute = false;
evalWaitInterval = 0;
originalRoute = null;
app.getWaypointHelper().setNewRoute(route);
app.runInUIThread(new Runnable() {
@Override
@ -401,6 +425,7 @@ public class RoutingHelper {
// 0. Route empty or needs to be extended? Then re-calculate route.
if(route.isEmpty()) {
calculateRoute = true;
//originalRoute = null;
} else {
// 1. Update current route position status according to latest received location
boolean finished = updateCurrentRouteStatus(currentLocation, posTolerance);
@ -989,6 +1014,7 @@ public class RoutingHelper {
if (res.isCalculated()) {
if (!params.inSnapToRoadMode && !params.inPublicTransportMode) {
route = res;
updateOriginalRoute();
}
if (params.resultListener != null) {
params.resultListener.onRouteCalculated(res);
@ -1094,6 +1120,12 @@ public class RoutingHelper {
}
}
private void updateOriginalRoute() {
if (originalRoute == null) {
originalRoute = route;
}
}
public void startRouteCalculationThread(RouteCalculationParams params, boolean paramsChanged, boolean updateProgress) {
synchronized (this) {
final Thread prevRunningJob = currentRunningJob;

View file

@ -157,6 +157,8 @@ public class NavigationFragment extends BaseSettingsFragment {
RouteProvider.RouteService routeService;
if (profileKey.equals(RoutingProfilesResources.STRAIGHT_LINE_MODE.name())) {
routeService = RouteProvider.RouteService.STRAIGHT;
} else if (profileKey.equals(RoutingProfilesResources.DIRECT_TO_MODE.name())){
routeService = RouteProvider.RouteService.DIRECT_TO;
} else if (profileKey.equals(RoutingProfilesResources.BROUTER_MODE.name())) {
routeService = RouteProvider.RouteService.BROUTER;
} else {
@ -209,6 +211,12 @@ public class NavigationFragment extends BaseSettingsFragment {
context.getString(R.string.special_routing_type),
RoutingProfilesResources.STRAIGHT_LINE_MODE.getIconRes(),
false, null));
profilesObjects.put(RoutingProfilesResources.DIRECT_TO_MODE.name(), new RoutingProfileDataObject(
RoutingProfilesResources.DIRECT_TO_MODE.name(),
context.getString(RoutingProfilesResources.DIRECT_TO_MODE.getStringRes()),
context.getString(R.string.special_routing_type),
RoutingProfilesResources.DIRECT_TO_MODE.getIconRes(),
false, null));
if (context.getBRouterService() != null) {
profilesObjects.put(RoutingProfilesResources.BROUTER_MODE.name(), new RoutingProfileDataObject(
RoutingProfilesResources.BROUTER_MODE.name(),

View file

@ -18,6 +18,7 @@ import android.support.v4.content.ContextCompat;
import android.util.Pair;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.data.QuadRect;
@ -45,6 +46,8 @@ import net.osmand.router.TransportRoutePlanner.TransportRouteResult;
import net.osmand.router.TransportRoutePlanner.TransportRouteResultSegment;
import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@ -68,6 +71,7 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
// keep array lists created
private List<Location> actionPoints = new ArrayList<Location>();
private List<TransportStop> routeTransportStops = new ArrayList<>();
private double[] lastProjectionOnPathPoint;
// cache
private Bitmap actionArrow;
@ -87,6 +91,8 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
private GeometryWayContext wayContext;
private LayerDrawable projectionIcon;
private final static Log log = PlatformUtil.getLog(RouteLayer.class);
public RouteLayer(RoutingHelper helper) {
this.helper = helper;
this.transportHelper = helper.getTransportRoutingHelper();
@ -309,6 +315,21 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
}
}
private void drawProjectionPoint(RotatedTileBox box, Canvas canvas, double[] projectionXY) {
if (projectionIcon == null) {
projectionIcon = (LayerDrawable) view.getResources().getDrawable(helper.getSettings().getApplicationMode().getLocationIcon().getIconId());
}
int locationX = (int) projectionXY[0];
int locationY = (int) projectionXY[1];
projectionIcon.setBounds(locationX - projectionIcon.getIntrinsicWidth() / 2,
locationY - projectionIcon.getIntrinsicHeight() / 2,
locationX + projectionIcon.getIntrinsicWidth() / 2,
locationY + projectionIcon.getIntrinsicHeight() / 2);
projectionIcon.draw(canvas);
}
@ColorInt
public int getRouteLineColor(boolean night) {
updateAttrs(new DrawSettings(night), view.getCurrentRotatedTileBox());
@ -820,7 +841,7 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
return simplifyPoints;
}
}
private class RouteSimplificationGeometry {
RouteCalculationResult route;
TransportRouteResult transportRoute;
@ -930,7 +951,7 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
}
private void drawSegments(RotatedTileBox tb, Canvas canvas, double topLatitude, double leftLongitude,
double bottomLatitude, double rightLongitude, Location lastProjection, int currentRoute) {
double bottomLatitude, double rightLongitude, Location lastProjection, int currentRoute, boolean showOriginalRoute) {
if (locations.size() == 0) {
return;
}
@ -951,12 +972,17 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
previousVisible = true;
}
}
List<Location> routeNodes = locations;
List<Location> routeNodes;
if (showOriginalRoute && helper.getOriginalRoute() != null && helper.getOriginalRouteAllLoc() != null) {
routeNodes = helper.getOriginalRouteAllLoc();
} else {
routeNodes = locations;
}
int previous = -1;
for (int i = currentRoute; i < routeNodes.size(); i++) {
Location ls = routeNodes.get(i);
style = getStyle(i, defaultWayStyle);
if (simplification.getQuick(i) == 0 && !styleMap.containsKey(i)) {
if (!showOriginalRoute && (simplification.getQuick(i) == 0 && !styleMap.containsKey(i))) {
continue;
}
if (leftLongitude <= ls.getLongitude() && ls.getLongitude() <= rightLongitude && bottomLatitude <= ls.getLatitude()
@ -1072,25 +1098,76 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
Location startLocation = new Location("transport");
startLocation.setLatitude(start.getLatitude());
startLocation.setLongitude(start.getLongitude());
routeGeometry.drawSegments(tb, canvas, topLatitude, leftLongitude, bottomLatitude, rightLongitude, startLocation, 0);
routeGeometry.drawSegments(tb, canvas, topLatitude, leftLongitude, bottomLatitude, rightLongitude, startLocation, 0, false);
}
} else {
RouteCalculationResult route = helper.getRoute();
routeGeometry.clearTransportRoute();
routeGeometry.updateRoute(tb, route);
routeGeometry.drawSegments(tb, canvas, topLatitude, leftLongitude, bottomLatitude, rightLongitude,
helper.getLastProjection(), route == null ? 0 : route.getCurrentRoute());
if (helper.getRoute().isShowOriginalRoute() && helper.getOriginalStartingLocation() != null) {
routeGeometry.drawSegments(tb, canvas, topLatitude, leftLongitude, bottomLatitude, rightLongitude,
helper.getOriginalStartingLocation(), 0, true);
} else {
routeGeometry.drawSegments(tb, canvas, topLatitude, leftLongitude, bottomLatitude, rightLongitude,
helper.getLastProjection(), route == null ? 0 : route.getCurrentRoute(), false);
}
List<RouteDirectionInfo> rd = helper.getRouteDirections();
Iterator<RouteDirectionInfo> it = rd.iterator();
if (tb.getZoom() >= 14) {
if (!helper.getRoute().isShowOriginalRoute() && tb.getZoom() >= 14) {
List<Location> actionPoints = calculateActionPoints(topLatitude, leftLongitude, bottomLatitude, rightLongitude, helper.getLastProjection(),
helper.getRoute().getRouteLocations(), helper.getRoute().getCurrentRoute(), it, tb.getZoom());
drawAction(tb, canvas, actionPoints);
}
if (helper.getRoute().isShowOriginalRoute()) {
//add projection point on original route
double[] projectionOnRoute = calculateProjectionOnRoutePoint(helper.getLastProjection(),
helper.getOriginalRouteAllLoc(), helper, tb);
if (projectionOnRoute != null) {
drawProjectionPoint(tb, canvas, projectionOnRoute);
}
}
}
}
private double[] calculateProjectionOnRoutePoint(Location lastProjection, List<Location> routeNodes, RoutingHelper helper, RotatedTileBox box) {
double[] projectionXY;
boolean visible;
Location previousInRoute = null;
Location nextInRoute = null;
//need to change this code by fixing helper.route.getCurrentRoute() miscalculation
if (helper.getRoute().getIntermediatePointsToPass() > 0) {
for (int i = 1; i < routeNodes.size(); i++) {
LatLon routePoint = new LatLon(routeNodes.get(i).getLatitude(), routeNodes.get(i).getLongitude());
if (routePoint.equals(helper.getIntermediatePoints().get(0))) {
previousInRoute = routeNodes.get(i - 1);
nextInRoute = routeNodes.get(i);
}
}
} else {
previousInRoute = routeNodes.get(routeNodes.size() - 2);
nextInRoute = routeNodes.get(routeNodes.size() - 1);
}
int centerX = box.getPixXFromLonNoRot(nextInRoute.getLongitude());
int centerY = box.getPixYFromLatNoRot(nextInRoute.getLatitude());
int aX = box.getPixXFromLonNoRot(lastProjection.getLongitude());
int aY = box.getPixYFromLatNoRot(lastProjection.getLatitude());
int bX = box.getPixXFromLonNoRot(previousInRoute.getLongitude());
int bY = box.getPixYFromLatNoRot(previousInRoute.getLatitude());
double radius = MapUtils.getVectorMagnitude(centerX, centerY, aX, aY);
double angle2 = MapUtils.getAngleForRadiusVector(centerX, centerY, bX, bY);
projectionXY = MapUtils.getCoordinatesFromRadiusAndAngle(centerX, centerY, radius, angle2);
visible = box.containsPoint((float)projectionXY[0], (float)projectionXY[1], 20.0f)
&& Math.abs(Math.toDegrees(MapUtils.getAngleBetweenVectors(centerX, centerY, aX, aY, centerX, centerY, bX, bY))) < 90;
if (visible) {
return projectionXY;
} else {
return null;
}
}
private List<Location> calculateActionPoints(double topLatitude, double leftLongitude, double bottomLatitude,
double rightLongitude, Location lastProjection, List<Location> routeNodes, int cd,