Merge pull request #9313 from osmandapp/analyze_gpx_fixes

Analyze gpx fixes
This commit is contained in:
vshcherb 2020-06-25 11:05:39 +02:00 committed by GitHub
commit 998bec38ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 210 additions and 87 deletions

View file

@ -22,11 +22,11 @@ import net.osmand.PlatformUtil;
import net.osmand.data.LatLon;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.MapMarkersHelper.MapMarkersGroup;
import net.osmand.plus.settings.backend.OsmandSettings.MetricsConstants;
import net.osmand.plus.activities.SavingTrackHelper;
import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
import net.osmand.plus.settings.backend.OsmandSettings.MetricsConstants;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
@ -639,6 +639,12 @@ public class GpxSelectionHelper {
selectedGPXFiles = newSelectedGPXFiles;
}
public void updateSelectedGpxFile(SelectedGpxFile selectedGpxFile) {
if (selectedGPXFiles.contains(selectedGpxFile)) {
saveCurrentSelections();
}
}
public SelectedGpxFile selectGpxFile(GPXFile gpx, boolean show, boolean notShowNavigationDialog) {
return selectGpxFile(gpx, show, notShowNavigationDialog, true, true, true);
}

View file

@ -100,7 +100,7 @@ public class SelectedGpxMenuBuilder extends MenuBuilder {
String min = OsmAndFormatter.getFormattedAlt(analysis.minElevation, app);
String max = OsmAndFormatter.getFormattedAlt(analysis.maxElevation, app);
buildRow(view, getThemedIcon(R.drawable.ic_action_altitude_range_16), null, app.getString(R.string.altitude_range),
buildRow(view, getThemedIcon(R.drawable.ic_action_altitude_range), null, app.getString(R.string.altitude_range),
min + " - " + max, 0, null,
false, null, false, 0, false, false, false, null, false);

View file

@ -57,7 +57,7 @@ public class SelectedGpxMenuController extends MenuController {
}
};
rightTitleButtonController.caption = mapActivity.getString(R.string.analyze_on_map);
rightTitleButtonController.startIconId = R.drawable.ic_action_track_16;
rightTitleButtonController.startIconId = R.drawable.ic_action_analyze_intervals;
}
private static class OpenGpxDetailsTask extends AsyncTask<Void, Void, GpxSelectionHelper.GpxDisplayItem> {

View file

@ -0,0 +1,46 @@
package net.osmand.plus.mapcontextmenu.other;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.data.LatLon;
import java.util.List;
public class TrackChartPoints {
private List<LatLon> xAxisPoints;
private LatLon highlightedPoint;
private int segmentColor;
private GPXFile gpx;
public List<LatLon> getXAxisPoints() {
return xAxisPoints;
}
public LatLon getHighlightedPoint() {
return highlightedPoint;
}
public int getSegmentColor() {
return segmentColor;
}
public GPXFile getGpx() {
return gpx;
}
public void setXAxisPoints(List<LatLon> xAxisPoints) {
this.xAxisPoints = xAxisPoints;
}
public void setHighlightedPoint(LatLon highlightedPoint) {
this.highlightedPoint = highlightedPoint;
}
public void setSegmentColor(int segmentColor) {
this.segmentColor = segmentColor;
}
public void setGpx(GPXFile gpx) {
this.gpx = gpx;
}
}

View file

@ -1,7 +1,9 @@
package net.osmand.plus.mapcontextmenu.other;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
@ -16,6 +18,7 @@ import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.listener.BarLineChartTouchListener;
import com.github.mikephil.charting.listener.ChartTouchListener.ChartGesture;
import com.github.mikephil.charting.listener.OnChartGestureListener;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
@ -26,6 +29,7 @@ import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.Location;
import net.osmand.data.LatLon;
import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
@ -39,6 +43,7 @@ import net.osmand.plus.helpers.GpxUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
import net.osmand.plus.helpers.GpxUiHelper.OrderedLineDataSet;
import net.osmand.plus.views.GPXLayer;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController;
@ -51,6 +56,8 @@ import static net.osmand.plus.SimplePopUpMenuItemAdapter.SimplePopUpMenuItem;
public class TrackDetailsMenu {
private static final int MAX_DISTANCE_LOCATION_PROJECTION = 20; // in meters
@Nullable
private MapActivity mapActivity;
@Nullable
@ -66,9 +73,7 @@ public class TrackDetailsMenu {
private int topMarginPx;
private boolean visible;
private boolean hidding;
public TrackDetailsMenu() {
}
private Location myLocation;
@Nullable
public MapActivity getMapActivity() {
@ -123,6 +128,35 @@ public class TrackDetailsMenu {
}
}
public void updateMyLocation(View mainView, Location location) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
LineChart chart = mainView.findViewById(R.id.chart);
GpxDisplayItem gpxItem = getGpxItem();
TrkSegment segment = getTrackSegment(chart);
LineData lineData = chart.getLineData();
List<ILineDataSet> ds = lineData != null ? lineData.getDataSets() : null;
if (ds != null && ds.size() > 0 && gpxItem != null && segment != null) {
RotatedTileBox tb = mapActivity.getMapView().getCurrentRotatedTileBox();
int mx = (int) tb.getPixXFromLatLon(location.getLatitude(), location.getLongitude());
int my = (int) tb.getPixYFromLatLon(location.getLatitude(), location.getLongitude());
int r = (int) (MAX_DISTANCE_LOCATION_PROJECTION * tb.getPixDensity());
WptPt point = GPXLayer.findPointNearSegment(tb, segment.points, r, mx, my);
if (point != null) {
int index = segment.points.indexOf(point);
gpxItem.locationOnMap = GPXLayer.createProjectionPoint(segment.points.get(index - 1), point, tb.getLatLonFromPixel(mx, my));
gpxItem.chartHighlightPos = (float) (gpxItem.locationOnMap.distance / ((OrderedLineDataSet) ds.get(0)).getDivX());
chart.highlightValue(gpxItem.chartHighlightPos, 0);
}
myLocation = location;
}
}
}
protected Location getMyLocation() {
return myLocation;
}
public void update() {
TrackDetailsMenuFragment fragment = getMenuFragment();
if (fragment != null) {
@ -516,6 +550,39 @@ public class TrackDetailsMenu {
}
});
final float minDragTriggerDist = AndroidUtils.dpToPx(app, 3);
chart.setOnTouchListener(new BarLineChartTouchListener(chart, chart.getViewPortHandler().getMatrixTouch(), 3f) {
private PointF touchStartPoint = new PointF();
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
saveTouchStart(event);
break;
case MotionEvent.ACTION_POINTER_DOWN:
if (event.getPointerCount() >= 2) {
saveTouchStart(event);
}
break;
case MotionEvent.ACTION_MOVE:
if (mTouchMode == NONE && mChart.hasNoDragOffset()) {
float touchDistance = distance(event.getX(), touchStartPoint.x, event.getY(), touchStartPoint.y);
if (Math.abs(touchDistance) > minDragTriggerDist) {
mTouchMode = DRAG;
}
}
break;
}
return super.onTouch(v, event);
}
private void saveTouchStart(MotionEvent event) {
touchStartPoint.x = event.getX();
touchStartPoint.y = event.getY();
}
});
chart.setOnChartGestureListener(new OnChartGestureListener() {
boolean hasTranslated = false;
float highlightDrawX = -1;
@ -775,43 +842,4 @@ public class TrackDetailsMenu {
return NO_COLOR;
}
}
public static class TrackChartPoints {
private List<LatLon> xAxisPoints;
private LatLon highlightedPoint;
private int segmentColor;
private GPXFile gpx;
public List<LatLon> getXAxisPoints() {
return xAxisPoints;
}
public LatLon getHighlightedPoint() {
return highlightedPoint;
}
public int getSegmentColor() {
return segmentColor;
}
public GPXFile getGpx() {
return gpx;
}
public void setXAxisPoints(List<LatLon> xAxisPoints) {
this.xAxisPoints = xAxisPoints;
}
public void setHighlightedPoint(LatLon highlightedPoint) {
this.highlightedPoint = highlightedPoint;
}
public void setSegmentColor(int segmentColor) {
this.segmentColor = segmentColor;
}
public void setGpx(GPXFile gpx) {
this.gpx = gpx;
}
}
}

View file

@ -14,25 +14,31 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.Location;
import net.osmand.plus.OsmAndLocationProvider.OsmAndLocationListener;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.util.MapUtils;
public class TrackDetailsMenuFragment extends BaseOsmAndFragment implements OsmAndLocationListener {
public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
public static final String TAG = "TrackDetailsMenuFragment";
private TrackDetailsMenu menu;
private View mainView;
private boolean paused = true;
private boolean nightMode;
private boolean locationUpdateStarted;
@Nullable
private MapActivity getMapActivity() {
return (MapActivity) getActivity();
@ -49,9 +55,7 @@ public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
MapActivity mapActivity = requireMapActivity();
menu = mapActivity.getTrackDetailsMenu();
nightMode = mapActivity.getMyApplication().getDaynightHelper().isNightModeForMapControls();
ContextThemeWrapper context =
new ContextThemeWrapper(mapActivity, !nightMode ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme);
View view = LayoutInflater.from(context).inflate(R.layout.track_details, container, false);
View view = UiUtilities.getInflater(mapActivity, nightMode).inflate(R.layout.track_details, container, false);
if (!AndroidUiHelper.isOrientationPortrait(mapActivity)) {
AndroidUtils.addStatusBarPadding21v(mapActivity, view);
}
@ -129,13 +133,44 @@ public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
} else {
menu.onShow();
}
paused = false;
startLocationUpdate();
}
@Override
public void onPause() {
super.onPause();
paused = true;
stopLocationUpdate();
}
private void startLocationUpdate() {
OsmandApplication app = getMyApplication();
if (app != null && !locationUpdateStarted) {
locationUpdateStarted = true;
app.getLocationProvider().addLocationListener(this);
}
}
private void stopLocationUpdate() {
OsmandApplication app = getMyApplication();
if (app != null && locationUpdateStarted) {
locationUpdateStarted = false;
app.getLocationProvider().removeLocationListener(this);
}
}
@Override
public void updateLocation(final Location location) {
if (location != null && !MapUtils.areLatLonEqual(menu.getMyLocation(), location)) {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null && mapActivity.getMapViewTrackingUtilities().isMapLinkedToLocation()) {
mapActivity.getMyApplication().runInUIThread(new Runnable() {
@Override
public void run() {
menu.updateMyLocation(mainView, location);
}
});
}
}
}
@Override
@ -151,10 +186,6 @@ public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
return R.color.status_bar_transparent_gradient;
}
public boolean isPaused() {
return paused;
}
public int getHeight() {
if (mainView != null) {
return mainView.getHeight();

View file

@ -68,7 +68,6 @@ import net.osmand.plus.OsmAndConstants;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
@ -82,6 +81,7 @@ import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
import net.osmand.plus.mapmarkers.CoordinateInputDialogFragment;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
import net.osmand.plus.osmedit.OsmEditingPlugin;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.util.Algorithms;
import java.io.File;
@ -1482,11 +1482,16 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
final SelectedGpxFile selectedGpxFile = selectedGpxHelper.getSelectedFileByPath(gpxInfo.file.getPath());
FileUtils.renameFile(getActivity(), gpxInfo.file, new RenameCallback() {
@Override
public void renamedTo(File file) {
asyncLoader = new LoadGpxTask();
asyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
if (selectedGpxFile != null && selectedGpxFile.getGpxFile() != null) {
selectedGpxFile.getGpxFile().path = file.getPath();
selectedGpxHelper.updateSelectedGpxFile(selectedGpxFile);
}
}
});
return true;

View file

@ -40,10 +40,9 @@ import net.osmand.plus.MapMarkersHelper.MapMarker;
import net.osmand.plus.MapMarkersHelper.MapMarkersGroup;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.base.PointImageDrawable;
import net.osmand.plus.mapcontextmenu.controllers.SelectedGpxMenuController.SelectedGpxPoint;
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu.TrackChartPoints;
import net.osmand.plus.mapcontextmenu.other.TrackChartPoints;
import net.osmand.plus.render.OsmandRenderer;
import net.osmand.plus.render.OsmandRenderer.RenderingContext;
import net.osmand.plus.settings.backend.OsmandSettings.CommonPreference;
@ -603,8 +602,11 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
for (TrkSegment segment : segments) {
QuadRect trackBounds = GPXUtilities.calculateBounds(segment.points);
if (QuadRect.trivialOverlap(tb.getLatLonBounds(), trackBounds)) {
SelectedGpxPoint selectedGpxPoint = findPointNearSegment(tb, selectedGpxFile, segment.points, r, mx, my);
if (selectedGpxPoint != null) {
WptPt nextPoint = findPointNearSegment(tb, segment.points, r, mx, my);
if (nextPoint != null) {
int index = segment.points.indexOf(nextPoint);
WptPt prevPoint = segment.points.get(index - 1);
SelectedGpxPoint selectedGpxPoint = createSelectedGpxPoint(selectedGpxFile, prevPoint, nextPoint, tb.getLatLonFromPixel(mx, my));
res.add(selectedGpxPoint);
break;
}
@ -613,7 +615,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
}
}
private SelectedGpxPoint findPointNearSegment(RotatedTileBox tb, SelectedGpxFile selectedGpxFile, List<WptPt> points, int r, int mx, int my) {
public static WptPt findPointNearSegment(RotatedTileBox tb, List<WptPt> points, int r, int mx, int my) {
WptPt firstPoint = points.get(0);
int ppx = (int) tb.getPixXFromLatLon(firstPoint.lat, firstPoint.lon);
int ppy = (int) tb.getPixYFromLatLon(firstPoint.lat, firstPoint.lon);
@ -625,7 +627,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
int py = (int) tb.getPixYFromLatLon(point.lat, point.lon);
int cross = placeInBbox(px, py, mx, my, r, r);
if (cross == 0) {
return createProjectionPoint(selectedGpxFile, points.get(i - 1), point, tb.getLatLonFromPixel(mx, my));
return point;
}
if ((pcross & cross) == 0) {
int mpx = px;
@ -636,7 +638,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
int mpynew = mpy / 2 + ppy / 2;
int mcrossnew = placeInBbox(mpxnew, mpynew, mx, my, r, r);
if (mcrossnew == 0) {
return createProjectionPoint(selectedGpxFile, points.get(i - 1), point, tb.getLatLonFromPixel(mx, my));
return point;
}
if ((mcrossnew & mcross) != 0) {
mpx = mpxnew;
@ -659,19 +661,8 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
return null;
}
private SelectedGpxPoint createProjectionPoint(SelectedGpxFile selectedGpxFile, WptPt prevPoint, WptPt nextPoint, LatLon latLon) {
LatLon projection = MapUtils.getProjection(latLon.getLatitude(), latLon.getLongitude(), prevPoint.lat, prevPoint.lon, nextPoint.lat, nextPoint.lon);
WptPt projectionPoint = new WptPt();
projectionPoint.lat = projection.getLatitude();
projectionPoint.lon = projection.getLongitude();
projectionPoint.heading = prevPoint.heading;
projectionPoint.distance = prevPoint.distance + MapUtils.getDistance(projection, prevPoint.lat, prevPoint.lon);
projectionPoint.ele = getValueByDistInterpolation(projectionPoint.distance, prevPoint.distance, prevPoint.ele, nextPoint.distance, nextPoint.ele);
projectionPoint.speed = getValueByDistInterpolation(projectionPoint.distance, prevPoint.distance, prevPoint.speed, nextPoint.distance, nextPoint.speed);
if (prevPoint.time != 0 && nextPoint.time != 0) {
projectionPoint.time = (long) getValueByDistInterpolation(projectionPoint.distance, prevPoint.distance, prevPoint.time, nextPoint.distance, nextPoint.time);
}
private SelectedGpxPoint createSelectedGpxPoint(SelectedGpxFile selectedGpxFile, WptPt prevPoint, WptPt nextPoint, LatLon latLon) {
WptPt projectionPoint = createProjectionPoint(prevPoint, nextPoint, latLon);
Location prevPointLocation = new Location("");
prevPointLocation.setLatitude(prevPoint.lat);
@ -686,11 +677,28 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
return new SelectedGpxPoint(selectedGpxFile, projectionPoint, prevPointLocation);
}
private double getValueByDistInterpolation(double projectionDist, double prevDist, double prevVal, double nextDist, double nextVal) {
public static WptPt createProjectionPoint(WptPt prevPoint, WptPt nextPoint, LatLon latLon) {
LatLon projection = MapUtils.getProjection(latLon.getLatitude(), latLon.getLongitude(), prevPoint.lat, prevPoint.lon, nextPoint.lat, nextPoint.lon);
WptPt projectionPoint = new WptPt();
projectionPoint.lat = projection.getLatitude();
projectionPoint.lon = projection.getLongitude();
projectionPoint.heading = prevPoint.heading;
projectionPoint.distance = prevPoint.distance + MapUtils.getDistance(projection, prevPoint.lat, prevPoint.lon);
projectionPoint.ele = getValueByDistInterpolation(projectionPoint.distance, prevPoint.distance, prevPoint.ele, nextPoint.distance, nextPoint.ele);
projectionPoint.speed = getValueByDistInterpolation(projectionPoint.distance, prevPoint.distance, prevPoint.speed, nextPoint.distance, nextPoint.speed);
if (prevPoint.time != 0 && nextPoint.time != 0) {
projectionPoint.time = (long) getValueByDistInterpolation(projectionPoint.distance, prevPoint.distance, prevPoint.time, nextPoint.distance, nextPoint.time);
}
return projectionPoint;
}
private static double getValueByDistInterpolation(double projectionDist, double prevDist, double prevVal, double nextDist, double nextVal) {
return prevVal + (projectionDist - prevDist) * ((nextVal - prevVal) / (nextDist - prevDist));
}
int placeInBbox(int x, int y, int mx, int my, int halfw, int halfh) {
private static int placeInBbox(int x, int y, int mx, int my, int halfw, int halfh) {
int cross = 0;
cross |= (x < mx - halfw ? 1 : 0);
cross |= (x > mx + halfw ? 2 : 0);

View file

@ -17,7 +17,7 @@ import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu.TrackChartPoints;
import net.osmand.plus.mapcontextmenu.other.TrackChartPoints;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.CompassRulerControlWidgetState;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopCoordinatesView;

View file

@ -36,8 +36,7 @@ import net.osmand.osm.edit.Way;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu;
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu.TrackChartPoints;
import net.osmand.plus.mapcontextmenu.other.TrackChartPoints;
import net.osmand.plus.profiles.LocationIcon;
import net.osmand.plus.render.RenderingIcons;
import net.osmand.plus.routing.RouteCalculationResult;
@ -104,7 +103,7 @@ public class RouteLayer extends OsmandMapLayer implements ContextMenuLayer.ICont
this.transportHelper = helper.getTransportRoutingHelper();
}
public void setTrackChartPoints(TrackDetailsMenu.TrackChartPoints trackChartPoints) {
public void setTrackChartPoints(TrackChartPoints trackChartPoints) {
this.trackChartPoints = trackChartPoints;
}