Fixed save/open gpx file (plan route)

This commit is contained in:
max-klaus 2020-08-20 21:55:47 +03:00
parent 51786f71f0
commit 71419a41e9
11 changed files with 231 additions and 312 deletions

View file

@ -404,6 +404,41 @@ public class RoutePlannerFrontEnd {
cleanupResultAndAddTurns(gctx);
}
public RouteSegmentResult generateStraightLineSegment(float averageSpeed, List<LatLon> points) {
RouteRegion reg = new RouteRegion();
reg.initRouteEncodingRule(0, "highway", RouteResultPreparation.UNMATCHED_HIGHWAY_TYPE);
RouteDataObject rdo = new RouteDataObject(reg);
int size = points.size();
TIntArrayList x = new TIntArrayList(size);
TIntArrayList y = new TIntArrayList(size);
double distance = 0;
double distOnRoadToPass = 0;
LatLon prev = null;
for (int i = 0; i < size; i++) {
LatLon l = points.get(i);
if (l != null) {
x.add(MapUtils.get31TileNumberX(l.getLongitude()));
y.add(MapUtils.get31TileNumberY(l.getLatitude()));
if (prev != null) {
double d = MapUtils.getDistance(l, prev);
distance += d;
distOnRoadToPass += d / averageSpeed;
}
}
prev = l;
}
rdo.pointsX = x.toArray();
rdo.pointsY = y.toArray();
rdo.types = new int[] { 0 } ;
rdo.id = -1;
RouteSegmentResult segment = new RouteSegmentResult(rdo, 0, rdo.getPointsLength() - 1);
segment.setSegmentTime((float) distOnRoadToPass);
segment.setSegmentSpeed(averageSpeed);
segment.setDistance((float) distance);
segment.setTurnType(TurnType.straight());
return segment;
}
public List<GpxPoint> generateGpxPoints(GpxRouteApproximation gctx, LocationsHolder locationsHolder) {
List<GpxPoint> gpxPoints = new ArrayList<>(locationsHolder.getSize());
GpxPoint prev = null;

View file

@ -9,17 +9,24 @@ import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.Location;
import net.osmand.LocationsHolder;
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
import net.osmand.data.LatLon;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.measurementtool.command.MeasurementCommandManager;
import net.osmand.plus.routing.RouteCalculationParams;
import net.osmand.plus.routing.RouteCalculationParams.RouteCalculationResultListener;
import net.osmand.plus.routing.RouteCalculationResult;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.routing.RoutingHelper.RouteCalculationProgressCallback;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.router.RouteCalculationProgress;
import net.osmand.router.RouteExporter;
import net.osmand.router.RouteImporter;
import net.osmand.router.RoutePlannerFrontEnd;
import net.osmand.router.RoutePlannerFrontEnd.GpxPoint;
import net.osmand.router.RoutePlannerFrontEnd.GpxRouteApproximation;
import net.osmand.router.RouteResultPreparation;
import net.osmand.router.RouteSegmentResult;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
@ -55,13 +62,12 @@ public class MeasurementEditingContext {
private WptPt originalPointToMove;
private boolean inAddPointMode;
private boolean needUpdateCacheForSnap;
private int calculatedPairs;
private CalculationMode calculationMode = WHOLE_TRACK;
private SnapToRoadProgressListener progressListener;
private ApplicationMode appMode = DEFAULT_APP_MODE;
private RouteCalculationProgress calculationProgress;
private final Queue<Pair<WptPt, WptPt>> snapToRoadPairsToCalculate = new ConcurrentLinkedQueue<>();
private final Queue<Pair<WptPt, WptPt>> roadSegmentsToCalculate = new ConcurrentLinkedQueue<>();
private final Map<Pair<WptPt, WptPt>, RoadSegmentData> roadSegmentData = new ConcurrentHashMap<>();
public enum CalculationMode {
@ -73,15 +79,31 @@ public class MeasurementEditingContext {
private ApplicationMode appMode;
private WptPt start;
private WptPt end;
private List<WptPt> snappedToRoadPoints = new ArrayList<>();
private List<RouteSegmentResult> snappedToRoadSegments = new ArrayList<>();
private List<WptPt> points;
private List<RouteSegmentResult> segments;
private double distance;
public RoadSegmentData(ApplicationMode appMode, WptPt start, WptPt end, List<WptPt> snappedToRoadPoints, List<RouteSegmentResult> snappedToRoadSegments) {
public RoadSegmentData(@NonNull ApplicationMode appMode, @NonNull WptPt start, @NonNull WptPt end,
@Nullable List<WptPt> points, @Nullable List<RouteSegmentResult> segments) {
this.appMode = appMode;
this.start = start;
this.end = end;
this.snappedToRoadPoints = snappedToRoadPoints;
this.snappedToRoadSegments = snappedToRoadSegments;
this.points = points;
this.segments = segments;
if (segments != null) {
double distance = 0;
for (RouteSegmentResult segment : segments) {
distance += segment.getDistance();
}
this.distance = distance;
} else if (points != null && points.size() > 1) {
double distance = 0;
for (int i = 1; i < points.size(); i++) {
distance += MapUtils.getDistance(points.get(i - 1).lat, points.get(i - 1).lon,
points.get(i).lat, points.get(i).lon);
}
this.distance = distance;
}
}
public ApplicationMode getAppMode() {
@ -96,12 +118,18 @@ public class MeasurementEditingContext {
return end;
}
public List<WptPt> getSnappedToRoadPoints() {
return Collections.unmodifiableList(snappedToRoadPoints);
@Nullable
public List<WptPt> getPoints() {
return points != null ? Collections.unmodifiableList(points) : null;
}
public List<RouteSegmentResult> getSnappedToRoadSegments() {
return Collections.unmodifiableList(snappedToRoadSegments);
@Nullable
public List<RouteSegmentResult> getSegments() {
return segments != null ? Collections.unmodifiableList(segments) : null;
}
public double getDistance() {
return distance;
}
}
@ -117,13 +145,8 @@ public class MeasurementEditingContext {
return inAddPointMode;
}
public boolean isNeedUpdateCacheForSnap() {
return needUpdateCacheForSnap;
}
public void setNeedUpdateCacheForSnap(boolean needUpdateCacheForSnap) {
this.needUpdateCacheForSnap = needUpdateCacheForSnap;
updateCacheForSnapIfNeeded(true);
public void updateCacheForSnap() {
updateCacheForSnap(true);
}
public int getSelectedPointPosition() {
@ -146,10 +169,6 @@ public class MeasurementEditingContext {
this.inAddPointMode = inAddPointMode;
}
boolean isInSnapToRoadMode() {
return appMode != DEFAULT_APP_MODE;
}
NewGpxData getNewGpxData() {
return newGpxData;
}
@ -191,6 +210,18 @@ public class MeasurementEditingContext {
this.appMode = DEFAULT_APP_MODE;
}
public double getRouteDistance() {
double distance = 0;
for (RoadSegmentData data : roadSegmentData.values()) {
distance += data.getDistance();
}
return distance;
}
public boolean hasRoute() {
return !roadSegmentData.isEmpty();
}
public void clearSnappedToRoadPoints() {
roadSegmentData.clear();
}
@ -233,22 +264,22 @@ public class MeasurementEditingContext {
after.points.clear();
before.points.addAll(points.subList(0, position));
after.points.addAll(points.subList(position, points.size()));
updateCacheForSnapIfNeeded(true);
updateCacheForSnap(true);
}
public void addPoint(WptPt pt) {
before.points.add(pt);
updateCacheForSnapIfNeeded(false);
updateCacheForSnap(false);
}
public void addPoint(int position, WptPt pt) {
before.points.add(position, pt);
updateCacheForSnapIfNeeded(false);
updateCacheForSnap(false);
}
public void addPoints(List<WptPt> points) {
before.points.addAll(points);
updateCacheForSnapIfNeeded(false);
updateCacheForSnap(false);
}
public WptPt removePoint(int position, boolean updateSnapToRoad) {
@ -257,7 +288,7 @@ public class MeasurementEditingContext {
}
WptPt pt = before.points.remove(position);
if (updateSnapToRoad) {
updateCacheForSnapIfNeeded(false);
updateCacheForSnap(false);
}
return pt;
}
@ -265,25 +296,17 @@ public class MeasurementEditingContext {
public void clearSegments() {
before.points.clear();
after.points.clear();
if (isInSnapToRoadMode()) {
if (beforeCacheForSnap != null && afterCacheForSnap != null) {
beforeCacheForSnap.points.clear();
afterCacheForSnap.points.clear();
}
needUpdateCacheForSnap = true;
} else {
beforeCacheForSnap = null;
afterCacheForSnap = null;
needUpdateCacheForSnap = false;
if (beforeCacheForSnap != null && afterCacheForSnap != null) {
beforeCacheForSnap.points.clear();
afterCacheForSnap.points.clear();
}
}
public void scheduleRouteCalculateIfNotEmpty() {
needUpdateCacheForSnap = true;
if (application == null || (before.points.size() == 0 && after.points.size() == 0)) {
return;
}
snapToRoadPairsToCalculate.clear();
roadSegmentsToCalculate.clear();
findPointsToCalculate(Arrays.asList(before.points, after.points));
RoutingHelper routingHelper = application.getRoutingHelper();
if (progressListener != null && !routingHelper.isRouteBeingCalculated()) {
@ -305,7 +328,7 @@ public class MeasurementEditingContext {
for (int i = 0; i < points.size() - 1; i++) {
Pair<WptPt, WptPt> pair = new Pair<>(points.get(i), points.get(i + 1));
if (roadSegmentData.get(pair) == null) {
snapToRoadPairsToCalculate.add(pair);
roadSegmentsToCalculate.add(pair);
}
}
}
@ -316,13 +339,11 @@ public class MeasurementEditingContext {
for (int i = 0; i < original.points.size() - 1; i++) {
Pair<WptPt, WptPt> pair = new Pair<>(original.points.get(i), original.points.get(i + 1));
RoadSegmentData data = this.roadSegmentData.get(pair);
List<WptPt> pts = data != null ? data.getSnappedToRoadPoints() : null;
List<WptPt> pts = data != null ? data.getPoints() : null;
if (pts != null) {
cache.points.addAll(pts);
} else {
if (isInSnapToRoadMode()) {
scheduleRouteCalculateIfNotEmpty();
}
scheduleRouteCalculateIfNotEmpty();
cache.points.addAll(Arrays.asList(pair.first, pair.second));
}
}
@ -348,25 +369,34 @@ public class MeasurementEditingContext {
if (startIndex < 0 || startIndex < prevPointIndex || startIndex >= points.size()) {
startIndex = findPointIndex(pair.first, points, prevPointIndex);
}
int endIndex = pair.second.getTrkPtIndex() + 1;
int endIndex = pair.second.getTrkPtIndex();
if (endIndex < 0 || endIndex < startIndex || endIndex >= points.size()) {
endIndex = findPointIndex(pair.second, points, startIndex);
}
if (startIndex >= 0 && endIndex >= 0) {
List<WptPt> segmentPoints = new ArrayList<>();
List<WptPt> pairPoints = new ArrayList<>();
for (int j = startIndex; j < endIndex && j < points.size(); j++) {
segmentPoints.add(points.get(j));
pairPoints.add(points.get(j));
prevPointIndex = j;
}
if (points.size() > prevPointIndex + 1) {
pairPoints.add(points.get(prevPointIndex + 1));
}
Iterator<RouteSegmentResult> it = segments.iterator();
int k = endIndex - startIndex;
while (it.hasNext() && k >= 0) {
RouteSegmentResult s = it.next();
it.remove();
k -= Math.abs(s.getEndPointIndex() - s.getStartPointIndex());
int k = endIndex - startIndex - 1;
List<RouteSegmentResult> pairSegments = new ArrayList<>();
if (k == 0 && !segments.isEmpty()) {
pairSegments.add(segments.remove(0));
} else {
while (it.hasNext() && k > 0) {
RouteSegmentResult s = it.next();
pairSegments.add(s);
it.remove();
k -= Math.abs(s.getEndPointIndex() - s.getStartPointIndex());
}
}
ApplicationMode appMode = ApplicationMode.valueOfStringKey(pair.first.getProfileType(), DEFAULT_APP_MODE);
roadSegmentData.put(pair, new RoadSegmentData(appMode, pair.first, pair.second, segmentPoints, segments));
roadSegmentData.put(pair, new RoadSegmentData(appMode, pair.first, pair.second, pairPoints, pairSegments));
}
}
addPoints(routePoints);
@ -443,18 +473,16 @@ public class MeasurementEditingContext {
&& newGpxData.getGpxFile().hasRoute();
}
private void updateCacheForSnapIfNeeded(boolean both) {
if (needUpdateCacheForSnap) {
recreateCacheForSnap(beforeCacheForSnap = new TrkSegment(), before);
if (both) {
recreateCacheForSnap(afterCacheForSnap = new TrkSegment(), after);
}
private void updateCacheForSnap(boolean both) {
recreateCacheForSnap(beforeCacheForSnap = new TrkSegment(), before);
if (both) {
recreateCacheForSnap(afterCacheForSnap = new TrkSegment(), after);
}
}
void cancelSnapToRoad() {
progressListener.hideProgressBar();
snapToRoadPairsToCalculate.clear();
roadSegmentsToCalculate.clear();
if (calculationProgress != null) {
calculationProgress.isCancelled = true;
}
@ -462,7 +490,7 @@ public class MeasurementEditingContext {
@Nullable
private RouteCalculationParams getParams() {
final Pair<WptPt, WptPt> currentPair = snapToRoadPairsToCalculate.poll();
final Pair<WptPt, WptPt> currentPair = roadSegmentsToCalculate.poll();
if (currentPair == null) {
return null;
}
@ -472,29 +500,25 @@ public class MeasurementEditingContext {
LatLon end = new LatLon(currentPair.second.getLatitude(), currentPair.second.getLongitude());
RouteRegion reg = new RouteRegion();
reg.initRouteEncodingRule(0, "highway", RouteResultPreparation.UNMATCHED_HIGHWAY_TYPE);
final RoutePlannerFrontEnd routePlannerFrontEnd = new RoutePlannerFrontEnd();
final RouteCalculationParams params = new RouteCalculationParams();
params.inSnapToRoadMode = true;
params.start = start;
ApplicationMode currentPointSnapToRoadMode;
if (calculationMode == NEXT_SEGMENT) {
currentPointSnapToRoadMode = ApplicationMode.valueOfStringKey(currentPair.first.getProfileType(),
null);
} else {
currentPointSnapToRoadMode = appMode;
ApplicationMode appMode = calculationMode == NEXT_SEGMENT
? ApplicationMode.valueOfStringKey(currentPair.first.getProfileType(), null) : this.appMode;
if (appMode == null) {
appMode = DEFAULT_APP_MODE;
}
params.end = end;
if (currentPointSnapToRoadMode == null) {
ApplicationMode straightLine = ApplicationMode.AIRCRAFT;
RoutingHelper.applyApplicationSettings(params, application.getSettings(), straightLine);
params.mode = straightLine;
} else {
RoutingHelper.applyApplicationSettings(params, application.getSettings(), currentPointSnapToRoadMode);
params.mode = currentPointSnapToRoadMode;
}
RoutingHelper.applyApplicationSettings(params, application.getSettings(), appMode);
params.mode = appMode;
params.ctx = application;
params.calculationProgress = calculationProgress = new RouteCalculationProgress();
params.calculationProgressCallback = new RoutingHelper.RouteCalculationProgressCallback() {
params.calculationProgressCallback = new RouteCalculationProgressCallback() {
@Override
public void start() {
@ -502,7 +526,7 @@ public class MeasurementEditingContext {
@Override
public void updateProgress(int progress) {
int pairs = calculatedPairs + snapToRoadPairsToCalculate.size();
int pairs = calculatedPairs + roadSegmentsToCalculate.size();
if (pairs != 0) {
int pairProgress = 100 / pairs;
progress = calculatedPairs * pairProgress + progress / pairs;
@ -519,7 +543,7 @@ public class MeasurementEditingContext {
calculatedPairs = 0;
}
};
params.resultListener = new RouteCalculationParams.RouteCalculationResultListener() {
params.resultListener = new RouteCalculationResultListener() {
@Override
public void onRouteCalculated(RouteCalculationResult route) {
List<Location> locations = route.getRouteLocations();
@ -538,11 +562,13 @@ public class MeasurementEditingContext {
pts.add(pt);
}
calculatedPairs++;
roadSegmentData.put(currentPair, new RoadSegmentData(route.getAppMode(), currentPair.first, currentPair.second, pts, route.getOriginalRoute()));
int trkptIndex = currentPair.first.getTrkPtIndex();
trkptIndex += pts.size() - 1;
currentPair.second.setTrkPtIndex(trkptIndex);
updateCacheForSnapIfNeeded(true);
List<RouteSegmentResult> originalRoute = route.getOriginalRoute();
if (Algorithms.isEmpty(originalRoute)) {
originalRoute = Collections.singletonList(routePlannerFrontEnd.generateStraightLineSegment(
DEFAULT_APP_MODE.getDefaultSpeed(), new LocationsHolder(pts).getLatLonList()));
}
roadSegmentData.put(currentPair, new RoadSegmentData(route.getAppMode(), currentPair.first, currentPair.second, pts, originalRoute));
updateCacheForSnap(true);
application.runInUIThread(new Runnable() {
@Override
public void run() {
@ -565,97 +591,29 @@ public class MeasurementEditingContext {
return params;
}
public void exportRouteAsGpx(@NonNull String gpxName, @Nullable ExportAsGpxListener exportListener) {
if (application == null || (before.points.size() == 0 && after.points.size() == 0)) {
return;
}
RoutingHelper routingHelper = application.getRoutingHelper();
if (!routingHelper.isRouteBeingCalculated()) {
RouteCalculationParams params = getExportAsGpxParams(gpxName, exportListener);
if (params != null) {
routingHelper.startRouteCalculationThread(params, true, true);
}
}
}
@Nullable
private RouteCalculationParams getExportAsGpxParams(@NonNull final String gpxName, @Nullable final ExportAsGpxListener exportListener) {
List<List<WptPt>> pointList = Arrays.asList(before.points, after.points);
WptPt startPoint = null;
WptPt endPoint = null;
List<WptPt> intermediatePoints = new ArrayList<>();
for (List<WptPt> points : pointList) {
for (WptPt point : points) {
if (startPoint == null) {
startPoint = point;
} else {
intermediatePoints.add(point);
endPoint = point;
}
}
}
if (endPoint != null) {
intermediatePoints.remove(endPoint);
}
if (startPoint == null || endPoint == null) {
public GPXFile exportRouteAsGpx(@NonNull String gpxName) {
if (application == null || before.points.isEmpty() || !hasRoute()) {
return null;
}
Location start = new Location("");
start.setLatitude(startPoint.getLatitude());
start.setLongitude(startPoint.getLongitude());
LatLon end = new LatLon(endPoint.getLatitude(), endPoint.getLongitude());
List<LatLon> intermediates = null;
if (!intermediatePoints.isEmpty()) {
intermediates = new ArrayList<>();
for (WptPt point : intermediatePoints) {
intermediates.add(new LatLon(point.getLatitude(), point.getLongitude()));
}
}
final RouteCalculationParams params = new RouteCalculationParams();
params.inSnapToRoadMode = true;
params.start = start;
params.end = end;
params.intermediates = intermediates;
if (appMode == null) {
ApplicationMode straightLine = ApplicationMode.AIRCRAFT;
RoutingHelper.applyApplicationSettings(params, application.getSettings(), straightLine);
params.mode = straightLine;
} else {
RoutingHelper.applyApplicationSettings(params, application.getSettings(), appMode);
params.mode = appMode;
}
params.ctx = application;
params.calculationProgress = calculationProgress = new RouteCalculationProgress();
params.calculationProgressCallback = new RoutingHelper.RouteCalculationProgressCallback() {
@Override
public void start() {
}
@Override
public void updateProgress(int progress) {
}
@Override
public void requestPrivateAccessRouting() {
}
@Override
public void finish() {
calculatedPairs = 0;
}
};
params.resultListener = new RouteCalculationParams.RouteCalculationResultListener() {
@Override
public void onRouteCalculated(RouteCalculationResult route) {
GPXFile gpx = application.getRoutingHelper().generateGPXFileWithRoute(route, gpxName);
if (exportListener != null) {
exportListener.onExportAsGpxFinished(gpx);
List<RouteSegmentResult> route = new ArrayList<>();
List<Location> locations = new ArrayList<>();
before.points.get(0).setTrkPtIndex(0);
int size = before.points.size();
for (int i = 0; i < size - 1; i++) {
Pair<WptPt, WptPt> pair = new Pair<>(before.points.get(i), before.points.get(i + 1));
RoadSegmentData data = this.roadSegmentData.get(pair);
if (data != null) {
LocationsHolder locationsHolder = new LocationsHolder(data.points);
locations.addAll(locationsHolder.getLocationsList());
pair.second.setTrkPtIndex(locations.size() - 1);
if (i < size - 2) {
locations.remove(locations.size() - 1);
}
route.addAll(data.segments);
}
};
return params;
}
return new RouteExporter(gpxName, route, locations, null).exportRoute();
}
interface SnapToRoadProgressListener {
@ -668,8 +626,4 @@ public class MeasurementEditingContext {
void refresh();
}
interface ExportAsGpxListener {
void onExportAsGpxFinished(GPXFile gpx);
}
}

View file

@ -43,7 +43,6 @@ import net.osmand.AndroidUtils;
import net.osmand.FileUtils;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.Route;
import net.osmand.GPXUtilities.Track;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.GPXUtilities.WptPt;
@ -70,8 +69,8 @@ import net.osmand.plus.measurementtool.SelectedPointBottomSheetDialogFragment.Se
import net.osmand.plus.measurementtool.adapter.MeasurementToolAdapter;
import net.osmand.plus.measurementtool.adapter.MeasurementToolAdapter.MeasurementAdapterListener;
import net.osmand.plus.measurementtool.command.AddPointCommand;
import net.osmand.plus.measurementtool.command.ChangeRouteModeCommand;
import net.osmand.plus.measurementtool.command.ApplyGpxApproximationCommand;
import net.osmand.plus.measurementtool.command.ChangeRouteModeCommand;
import net.osmand.plus.measurementtool.command.ClearPointsCommand;
import net.osmand.plus.measurementtool.command.MovePointCommand;
import net.osmand.plus.measurementtool.command.RemovePointCommand;
@ -96,7 +95,6 @@ import java.util.Locale;
import static net.osmand.IndexConstants.GPX_FILE_EXT;
import static net.osmand.plus.measurementtool.MeasurementEditingContext.CalculationMode;
import static net.osmand.plus.measurementtool.MeasurementEditingContext.ExportAsGpxListener;
import static net.osmand.plus.measurementtool.MeasurementEditingContext.SnapToRoadProgressListener;
import static net.osmand.plus.measurementtool.SelectFileBottomSheet.Mode.ADD_TO_TRACK;
import static net.osmand.plus.measurementtool.SelectFileBottomSheet.Mode.OPEN_TRACK;
@ -297,7 +295,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
OptionsBottomSheetDialogFragment.showInstance(mapActivity.getSupportFragmentManager(),
MeasurementToolFragment.this,
editingCtx.isTrackSnappedToRoad() || editingCtx.isNewData(),
editingCtx.isInSnapToRoadMode(),
editingCtx.getAppMode().getStringKey()
);
}
@ -416,9 +413,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
@Override
public void onClick(View v) {
if (editingCtx.getPointsCount() > 0) {
if (newGpxData != null && newGpxData.getActionType() == ActionType.EDIT_SEGMENT
&& editingCtx.isInSnapToRoadMode()) {
openSaveAsNewTrackMenu(mapActivity);
if (newGpxData != null && newGpxData.getActionType() == ActionType.EDIT_SEGMENT) {
openSaveAsNewTrackMenu(mapActivity);
} else {
if (newGpxData == null) {
final File dir = mapActivity.getMyApplication().getAppPath(IndexConstants.GPX_INDEX_DIR);
@ -488,7 +484,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
if (!points.isEmpty()) {
ApplicationMode snapToRoadAppMode = ApplicationMode.valueOfStringKey(points.get(points.size() - 1).getProfileType(), null);
if (snapToRoadAppMode != null) {
setSnapToRoadMode(snapToRoadAppMode);
setAppMode(snapToRoadAppMode);
}
}
ActionType actionType = newGpxData.getActionType();
@ -604,7 +600,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
toolBarController.setTitle(getString(R.string.route_between_points));
mapActivity.refreshMap();
if (editingCtx.isNewData() || editingCtx.hasRoutePoints() || editingCtx.isInSnapToRoadMode()) {
if (editingCtx.isNewData() || editingCtx.hasRoutePoints() || editingCtx.hasRoute()) {
RouteBetweenPointsBottomSheetDialogFragment.showInstance(mapActivity.getSupportFragmentManager(),
this, editingCtx.getCalculationMode(),
editingCtx.getAppMode());
@ -670,12 +666,10 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
if (editingCtx.getPointsCount() > 0) {
if (editingCtx.isInSnapToRoadMode()) {
editingCtx.getPoints().clear();
editingCtx.getPoints().addAll(editingCtx.getBeforePoints());
editingCtx.getBeforePoints().clear();
editingCtx.getBeforePoints().addAll(editingCtx.getBeforeTrkSegmentLine().points);
}
editingCtx.getPoints().clear();
editingCtx.getPoints().addAll(editingCtx.getBeforePoints());
editingCtx.getBeforePoints().clear();
editingCtx.getBeforePoints().addAll(editingCtx.getBeforeTrkSegmentLine().points);
if (editingCtx.isNewData()) {
saveAsGpx(SaveType.ROUTE_POINT);
} else {
@ -779,13 +773,11 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
}
@Override
public void onCloseRouteDialog(boolean snapToRoadEnabled) {
if (!snapToRoadEnabled && !editingCtx.isInSnapToRoadMode()) {
toolBarController.setTitle(previousToolBarTitle);
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.refreshMap();
}
public void onCloseRouteDialog() {
toolBarController.setTitle(previousToolBarTitle);
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.refreshMap();
}
}
@ -984,13 +976,13 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
};
}
private void setSnapToRoadMode(@NonNull ApplicationMode appMode) {
private void setAppMode(@NonNull ApplicationMode appMode) {
editingCtx.setAppMode(appMode);
editingCtx.scheduleRouteCalculateIfNotEmpty();
updateSnapToRoadControls();
}
private void resetSnapToRoadMode() {
private void resetAppMode() {
toolBarController.setTopBarSwitchVisible(false);
toolBarController.setTitle(previousToolBarTitle);
mainIcon.setImageDrawable(getActiveIcon(R.drawable.ic_action_ruler));
@ -1462,8 +1454,6 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
private ProgressDialog progressDialog;
private File toSave;
private boolean exportRouteAsGpx = false;
@Override
protected void onPreExecute() {
cancelModes();
@ -1492,44 +1482,20 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
if (measurementLayer != null) {
if (saveType == SaveType.LINE) {
TrkSegment segment = new TrkSegment();
if (editingCtx.isInSnapToRoadMode()) {
segment.points.addAll(before.points);
segment.points.addAll(after.points);
} else {
segment.points.addAll(points);
}
segment.points.addAll(before.points);
segment.points.addAll(after.points);
Track track = new Track();
track.name = trackName;
track.segments.add(segment);
gpx.tracks.add(track);
} else if (saveType == SaveType.ROUTE_POINT) {
if (editingCtx.isInSnapToRoadMode()) {
exportRouteAsGpx = true;
editingCtx.exportRouteAsGpx(trackName, new ExportAsGpxListener() {
@Override
public void onExportAsGpxFinished(GPXFile gpx) {
gpx.addRoutePoints(editingCtx.getPoints());
final Exception res = GPXUtilities.writeGpxFile(toSave, gpx);
gpx.path = toSave.getAbsolutePath();
OsmandApplication app = getMyApplication();
if (showOnMap && app != null) {
app.getSelectedGpxHelper().selectGpxFile(gpx, true, false);
app.runInUIThread(new Runnable() {
@Override
public void run() {
onGpxSaved(res);
}
});
}
}
});
return null;
} else {
Route rt = new Route();
rt.name = trackName;
gpx.routes.add(rt);
rt.points.addAll(points);
if (editingCtx.hasRoute()) {
GPXFile newGpx = editingCtx.exportRouteAsGpx(trackName);
if (newGpx != null) {
gpx = newGpx;
}
}
gpx.addRoutePoints(points);
}
}
Exception res = GPXUtilities.writeGpxFile(toSave, gpx);
@ -1543,32 +1509,32 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
if (measurementLayer != null) {
if (actionType != null) {
switch (actionType) {
case ADD_SEGMENT:
if (editingCtx.isInSnapToRoadMode()) {
List<WptPt> snappedPoints = new ArrayList<>();
snappedPoints.addAll(before.points);
snappedPoints.addAll(after.points);
gpx.addTrkSegment(snappedPoints);
} else {
gpx.addTrkSegment(points);
}
case ADD_SEGMENT: {
List<WptPt> snappedPoints = new ArrayList<>();
snappedPoints.addAll(before.points);
snappedPoints.addAll(after.points);
gpx.addTrkSegment(snappedPoints);
break;
case ADD_ROUTE_POINTS:
}
case ADD_ROUTE_POINTS: {
gpx.replaceRoutePoints(points);
break;
case EDIT_SEGMENT:
}
case EDIT_SEGMENT: {
TrkSegment segment = new TrkSegment();
segment.points.addAll(points);
gpx.replaceSegment(editingCtx.getNewGpxData().getTrkSegment(), segment);
break;
case OVERWRITE_SEGMENT:
}
case OVERWRITE_SEGMENT: {
List<WptPt> snappedPoints = new ArrayList<>();
snappedPoints.addAll(before.points);
snappedPoints.addAll(after.points);
TrkSegment segment1 = new TrkSegment();
segment1.points.addAll(snappedPoints);
gpx.replaceSegment(editingCtx.getNewGpxData().getTrkSegment(), segment1);
TrkSegment segment = new TrkSegment();
segment.points.addAll(snappedPoints);
gpx.replaceSegment(editingCtx.getNewGpxData().getTrkSegment(), segment);
break;
}
}
} else {
gpx.addRoutePoints(points);
@ -1589,9 +1555,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
@Override
protected void onPostExecute(Exception warning) {
if (!exportRouteAsGpx) {
onGpxSaved(warning);
}
onGpxSaved(warning);
}
private void onGpxSaved(Exception warning) {
@ -1663,7 +1627,8 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
private void updateDistancePointsText() {
MeasurementToolLayer measurementLayer = getMeasurementLayer();
if (measurementLayer != null) {
distanceTv.setText(measurementLayer.getDistanceSt() + ",");
String distanceStr = OsmAndFormatter.getFormattedDistance((float) editingCtx.getRouteDistance(), requireMyApplication());
distanceTv.setText(distanceStr + ",");
pointsTv.setText((portrait ? pointsSt + ": " : "") + editingCtx.getPointsCount());
}
updateToolbar();
@ -1780,11 +1745,7 @@ public class MeasurementToolFragment extends BaseOsmAndFragment implements Route
if (pointsListOpened) {
hidePointsList();
}
if (editingCtx.isInSnapToRoadMode()) {
resetSnapToRoadMode();
} else {
visibleSnapToRoadIcon(false);
}
resetAppMode();
if (!editingCtx.isNewData() && !planRouteMode) {
GPXFile gpx = editingCtx.getNewGpxData().getGpxFile();
Intent newIntent = new Intent(mapActivity, mapActivity.getMyApplication().getAppCustomization().getTrackActivity());

View file

@ -13,13 +13,12 @@ import net.osmand.Location;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.data.RotatedTileBox;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.R;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.views.layers.ContextMenuLayer;
import net.osmand.plus.views.OsmandMapLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.Renderable;
import net.osmand.plus.views.layers.ContextMenuLayer;
import net.osmand.plus.views.layers.geometry.GeometryWay;
import net.osmand.util.MapUtils;
@ -100,18 +99,6 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
this.inMeasurementMode = inMeasurementMode;
}
String getDistanceSt() {
float dist = 0;
List<WptPt> points = editingCtx.getBeforeTrkSegmentLine().points;
if (points.size() > 0) {
for (int i = 1; i < points.size(); i++) {
dist += MapUtils.getDistance(points.get(i - 1).lat, points.get(i - 1).lon,
points.get(i).lat, points.get(i).lon);
}
}
return OsmAndFormatter.getFormattedDistance(dist, view.getApplication());
}
@Override
public boolean onSingleTap(PointF point, RotatedTileBox tileBox) {
if (inMeasurementMode && editingCtx.getSelectedPointPosition() == -1) {
@ -305,13 +292,9 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
private void drawCenterIcon(Canvas canvas, RotatedTileBox tb, boolean nightMode) {
canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
if (nightMode) {
canvas.drawBitmap(centerIconNight, tb.getCenterPixelX() - centerIconNight.getWidth() / 2f,
tb.getCenterPixelY() - centerIconNight.getHeight() / 2f, bitmapPaint);
} else {
canvas.drawBitmap(centerIconDay, tb.getCenterPixelX() - centerIconDay.getWidth() / 2f,
tb.getCenterPixelY() - centerIconDay.getHeight() / 2f, bitmapPaint);
}
Bitmap centerBmp = nightMode ? centerIconNight : centerIconDay;
canvas.drawBitmap(centerBmp, tb.getCenterPixelX() - centerBmp.getWidth() / 2f,
tb.getCenterPixelY() - centerBmp.getHeight() / 2f, bitmapPaint);
canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
}

View file

@ -27,7 +27,6 @@ public class OptionsBottomSheetDialogFragment extends MenuBottomSheetDialogFragm
public static final String TAG = OptionsBottomSheetDialogFragment.class.getSimpleName();
private static final Log LOG = PlatformUtil.getLog(OptionsBottomSheetDialogFragment.class);
public static final String SNAP_TO_ROAD_ENABLED_KEY = "snap_to_road_enabled";
public static final String TRACK_SNAPPED_TO_ROAD_KEY = "track_snapped_to_road";
public static final String SNAP_TO_ROAD_APP_MODE_KEY = "snap_to_road_app_mode";
@ -36,10 +35,8 @@ public class OptionsBottomSheetDialogFragment extends MenuBottomSheetDialogFragm
@Override
public void createMenuItems(Bundle savedInstanceState) {
Bundle args = getArguments();
boolean snapToRoadEnabled = false;
boolean trackSnappedToRoad = false;
if (args != null) {
snapToRoadEnabled = args.getBoolean(SNAP_TO_ROAD_ENABLED_KEY);
trackSnappedToRoad = args.getBoolean(TRACK_SNAPPED_TO_ROAD_KEY);
routeAppMode = ApplicationMode.valueOfStringKey(args.getString(SNAP_TO_ROAD_APP_MODE_KEY), null);
}
@ -49,7 +46,7 @@ public class OptionsBottomSheetDialogFragment extends MenuBottomSheetDialogFragm
String description;
Drawable icon;
if (trackSnappedToRoad) {
if (!snapToRoadEnabled || routeAppMode == null) {
if (routeAppMode == null || routeAppMode == MeasurementEditingContext.DEFAULT_APP_MODE) {
description = getString(R.string.routing_profile_straightline);
icon = getContentIcon(R.drawable.ic_action_split_interval);
} else {
@ -165,14 +162,13 @@ public class OptionsBottomSheetDialogFragment extends MenuBottomSheetDialogFragm
params.rightMargin = view.getContext().getResources().getDimensionPixelSize(R.dimen.bottom_sheet_icon_margin_large);
}
public static void showInstance(@NonNull FragmentManager fm, Fragment targetFragment, boolean trackSnappedToRoad,
boolean snapToRoad, String routeAppModeStringKey) {
public static void showInstance(@NonNull FragmentManager fm, Fragment targetFragment,
boolean trackSnappedToRoad, String routeAppModeStringKey) {
try {
if (!fm.isStateSaved()) {
OptionsBottomSheetDialogFragment fragment = new OptionsBottomSheetDialogFragment();
Bundle args = new Bundle();
args.putBoolean(TRACK_SNAPPED_TO_ROAD_KEY, trackSnappedToRoad);
args.putBoolean(SNAP_TO_ROAD_ENABLED_KEY, snapToRoad);
args.putString(SNAP_TO_ROAD_APP_MODE_KEY, routeAppModeStringKey);
fragment.setArguments(args);
fragment.setTargetFragment(targetFragment,0);

View file

@ -49,10 +49,9 @@ public class RouteBetweenPointsBottomSheetDialogFragment extends BottomSheetDial
private boolean nightMode;
private boolean portrait;
private boolean snapToRoadEnabled = true;
private TextView btnDescription;
private CalculationMode calculationMode = WHOLE_TRACK;
private ApplicationMode snapToRoadAppMode;
private ApplicationMode appMode;
private LinearLayout customRadioButton;
@ -61,7 +60,7 @@ public class RouteBetweenPointsBottomSheetDialogFragment extends BottomSheetDial
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Bundle args = getArguments();
if (args != null) {
snapToRoadAppMode = ApplicationMode.valueOfStringKey(args.getString(ROUTE_APP_MODE_KEY), null);
appMode = ApplicationMode.valueOfStringKey(args.getString(ROUTE_APP_MODE_KEY), null);
calculationMode = (CalculationMode) args.get(CALCULATION_MODE_KEY);
}
if (savedInstanceState != null) {
@ -102,11 +101,9 @@ public class RouteBetweenPointsBottomSheetDialogFragment extends BottomSheetDial
View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
snapToRoadEnabled = false;
ApplicationMode mode = DEFAULT_APP_MODE;
if ((int) view.getTag() != STRAIGHT_LINE_TAG) {
mode = modes.get((int) view.getTag());
snapToRoadEnabled = true;
}
Fragment fragment = getTargetFragment();
if (fragment instanceof RouteBetweenPointsFragmentListener) {
@ -118,13 +115,13 @@ public class RouteBetweenPointsBottomSheetDialogFragment extends BottomSheetDial
Drawable icon = app.getUIUtilities().getIcon(R.drawable.ic_action_split_interval, nightMode);
addProfileView(navigationType, onClickListener, STRAIGHT_LINE_TAG, icon,
app.getText(R.string.routing_profile_straightline), snapToRoadAppMode == DEFAULT_APP_MODE);
app.getText(R.string.routing_profile_straightline), appMode == DEFAULT_APP_MODE);
addDelimiterView(navigationType);
for (int i = 0; i < modes.size(); i++) {
ApplicationMode mode = modes.get(i);
icon = app.getUIUtilities().getIcon(mode.getIconRes(), mode.getIconColorInfo().getColor(nightMode));
addProfileView(navigationType, onClickListener, i, icon, mode.toHumanString(), mode.equals(snapToRoadAppMode));
addProfileView(navigationType, onClickListener, i, icon, mode.toHumanString(), mode.equals(appMode));
}
segmentBtn.setOnClickListener(new View.OnClickListener() {
@ -202,7 +199,7 @@ public class RouteBetweenPointsBottomSheetDialogFragment extends BottomSheetDial
public void onDestroyView() {
Fragment fragment = getTargetFragment();
if (fragment instanceof RouteBetweenPointsFragmentListener) {
((RouteBetweenPointsFragmentListener) fragment).onCloseRouteDialog(snapToRoadEnabled);
((RouteBetweenPointsFragmentListener) fragment).onCloseRouteDialog();
}
super.onDestroyView();
}
@ -230,7 +227,7 @@ public class RouteBetweenPointsBottomSheetDialogFragment extends BottomSheetDial
public interface RouteBetweenPointsFragmentListener {
void onCloseRouteDialog(boolean snapToRoadEnabled);
void onCloseRouteDialog();
void onChangeApplicationMode(ApplicationMode mode, CalculationMode calculationMode);

View file

@ -15,7 +15,6 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand {
private ApplicationMode mode;
private GpxRouteApproximation approximation;
private List<WptPt> points;
private boolean needUpdateCache;
public ApplyGpxApproximationCommand(MeasurementToolLayer measurementLayer, GpxRouteApproximation approximation, ApplicationMode mode) {
super(measurementLayer);
@ -31,7 +30,6 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand {
@Override
public boolean execute() {
List<WptPt> pts = getEditingCtx().getPoints();
needUpdateCache = getEditingCtx().isNeedUpdateCacheForSnap();
points = new ArrayList<>(pts);
applyApproximation();
refreshMap();
@ -55,9 +53,7 @@ public class ApplyGpxApproximationCommand extends MeasurementModeCommand {
getEditingCtx().resetAppMode();
getEditingCtx().clearSegments();
getEditingCtx().addPoints(points);
if (needUpdateCache) {
getEditingCtx().setNeedUpdateCacheForSnap(true);
}
getEditingCtx().updateCacheForSnap();
refreshMap();
}

View file

@ -48,7 +48,7 @@ public class ChangeRouteModeCommand extends MeasurementModeCommand {
editingCtx.clearSnappedToRoadPoints();
}
editingCtx.setCalculationMode(oldCalculationMode);
editingCtx.setNeedUpdateCacheForSnap(true);
editingCtx.updateCacheForSnap();
}
@Override
@ -75,6 +75,6 @@ public class ChangeRouteModeCommand extends MeasurementModeCommand {
if (newCalculationMode == CalculationMode.WHOLE_TRACK) {
editingCtx.clearSnappedToRoadPoints();
}
editingCtx.setNeedUpdateCacheForSnap(true);
editingCtx.updateCacheForSnap();
}
}

View file

@ -4,13 +4,11 @@ import net.osmand.GPXUtilities.WptPt;
import net.osmand.plus.measurementtool.MeasurementToolLayer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ClearPointsCommand extends MeasurementModeCommand {
private List<WptPt> points;
private boolean needUpdateCache;
public ClearPointsCommand(MeasurementToolLayer measurementLayer) {
super(measurementLayer);
@ -19,7 +17,6 @@ public class ClearPointsCommand extends MeasurementModeCommand {
@Override
public boolean execute() {
List<WptPt> pts = getEditingCtx().getPoints();
needUpdateCache = getEditingCtx().isNeedUpdateCacheForSnap();
points = new ArrayList<>(pts);
pts.clear();
getEditingCtx().clearSegments();
@ -30,9 +27,7 @@ public class ClearPointsCommand extends MeasurementModeCommand {
@Override
public void undo() {
getEditingCtx().addPoints(points);
if (needUpdateCache) {
getEditingCtx().setNeedUpdateCacheForSnap(true);
}
getEditingCtx().updateCacheForSnap();
refreshMap();
}

View file

@ -18,7 +18,7 @@ public class ReorderPointCommand extends MeasurementModeCommand {
@Override
public boolean execute() {
getEditingCtx().setNeedUpdateCacheForSnap(true);
getEditingCtx().updateCacheForSnap();
refreshMap();
return true;
}
@ -36,7 +36,7 @@ public class ReorderPointCommand extends MeasurementModeCommand {
private void reorder(int addTo, int removeFrom) {
List<WptPt> points = getEditingCtx().getPoints();
points.add(addTo, points.remove(removeFrom));
getEditingCtx().setNeedUpdateCacheForSnap(true);
getEditingCtx().updateCacheForSnap();
refreshMap();
}

View file

@ -1,6 +1,7 @@
package net.osmand.plus.routing;
import android.content.Context;
import androidx.annotation.Nullable;
import net.osmand.Location;
@ -11,10 +12,11 @@ import net.osmand.binary.RouteDataObject;
import net.osmand.data.LatLon;
import net.osmand.data.LocationPoint;
import net.osmand.data.QuadRect;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.routing.AlarmInfo.AlarmInfoType;
import net.osmand.plus.routing.RouteProvider.RouteService;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.router.ExitInfo;
import net.osmand.router.RouteSegmentResult;
import net.osmand.router.RoutingContext;
@ -61,7 +63,7 @@ public class RouteCalculationResult {
// params
protected final ApplicationMode appMode;
protected final RouteProvider.RouteService routeService;
protected final RouteService routeService;
protected final double routeRecalcDistance;
protected final double routeVisibleAngle;
@ -128,7 +130,7 @@ public class RouteCalculationResult {
this.routeService = params.mode.getRouteService();
if(params.ctx != null) {
this.routeRecalcDistance = params.ctx.getSettings().ROUTE_RECALCULATION_DISTANCE.getModeValue(params.mode);
this.routeVisibleAngle = routeService == RouteProvider.RouteService.STRAIGHT ?
this.routeVisibleAngle = routeService == RouteService.STRAIGHT ?
params.ctx.getSettings().ROUTE_STRAIGHT_ANGLE.getModeValue(params.mode) : 0;
} else {
this.routeRecalcDistance = 0;
@ -178,7 +180,7 @@ public class RouteCalculationResult {
updateDirectionsTime(this.directions, this.listDistance);
this.alarmInfo = Collections.unmodifiableList(alarms);
this.routeRecalcDistance = ctx.getSettings().ROUTE_RECALCULATION_DISTANCE.getModeValue(mode);
this.routeVisibleAngle = routeService == RouteProvider.RouteService.STRAIGHT ?
this.routeVisibleAngle = routeService == RouteService.STRAIGHT ?
ctx.getSettings().ROUTE_STRAIGHT_ANGLE.getModeValue(mode) : 0;
}
@ -276,7 +278,7 @@ public class RouteCalculationResult {
return routeRecalcDistance;
}
public RouteProvider.RouteService getRouteService() {
public RouteService getRouteService() {
return routeService;
}