basic implementation
This commit is contained in:
parent
08b7813ef4
commit
db4f832b04
7 changed files with 191 additions and 17 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ public class RoutingProfileDataObject extends ProfileDataObject {
|
|||
}
|
||||
|
||||
public enum RoutingProfilesResources {
|
||||
STRAIGHT_TO_LINE_MODE(R.string.routing_profile_straight_to, R.drawable.ic_action_split_interval),
|
||||
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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -63,6 +63,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;
|
||||
|
@ -76,7 +78,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;
|
||||
|
@ -108,6 +110,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,
|
||||
|
@ -1154,5 +1158,8 @@ public class RouteCalculationResult {
|
|||
public int imminent;
|
||||
private int directionInfoInd;
|
||||
}
|
||||
|
||||
|
||||
public boolean isShowOriginalRoute() {
|
||||
return showOriginalRoute;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,8 @@ public class RouteProvider {
|
|||
public enum RouteService {
|
||||
OSMAND("OsmAnd (offline)"),
|
||||
BROUTER("BRouter (offline)"),
|
||||
STRAIGHT("Straight line");
|
||||
STRAIGHT("Straight line"),
|
||||
STRAIGHT_TO("Straight 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.STRAIGHT_TO) {
|
||||
res = findStraightTo(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 findStraightTo(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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,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;
|
||||
|
@ -174,6 +177,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);
|
||||
|
@ -181,10 +185,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
|
||||
|
@ -399,6 +423,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);
|
||||
|
@ -987,6 +1012,7 @@ public class RoutingHelper {
|
|||
if (res.isCalculated()) {
|
||||
if (!params.inSnapToRoadMode && !params.inPublicTransportMode) {
|
||||
route = res;
|
||||
updateOriginalRoute();
|
||||
}
|
||||
if (params.resultListener != null) {
|
||||
params.resultListener.onRouteCalculated(res);
|
||||
|
@ -1092,6 +1118,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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
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,8 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
|
|||
return simplifyPoints;
|
||||
}
|
||||
}
|
||||
|
||||
private final static Log log = PlatformUtil.getLog(RouteLayer.class);
|
||||
|
||||
private class RouteSimplificationGeometry {
|
||||
RouteCalculationResult route;
|
||||
TransportRouteResult transportRoute;
|
||||
|
@ -930,7 +952,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 +973,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 +1099,67 @@ 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()) {
|
||||
routeGeometry.drawSegments(tb, canvas, topLatitude, leftLongitude, bottomLatitude, rightLongitude,
|
||||
helper.getOriginalStartingLocation(), route == null ? 0 : route.getCurrentRoute(), 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.getRoute().getCurrentRoute(), tb);
|
||||
if (projectionOnRoute != null) {
|
||||
log.debug("Draw projection");
|
||||
drawProjectionPoint(tb, canvas, projectionOnRoute);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private double[] calculateProjectionOnRoutePoint(Location lastProjection, List<Location> routeNodes, int cd, RotatedTileBox box) {
|
||||
|
||||
double[] projectionXY = new double[2];
|
||||
boolean visible = false;
|
||||
if (cd < routeNodes.size() - 1) {
|
||||
Location previousInRoute = routeNodes.get(cd);
|
||||
Location nextInRoute = routeNodes.get(cd + 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);
|
||||
log.debug("Projection: " + projectionXY[0] + ", " + projectionXY[1]);
|
||||
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,
|
||||
|
|
Loading…
Reference in a new issue