Add my location projection to analyze gpx screen
This commit is contained in:
parent
f4bcbc46a6
commit
1cce2705ee
5 changed files with 110 additions and 40 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -26,6 +26,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 +40,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 +53,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 +70,7 @@ public class TrackDetailsMenu {
|
|||
private int topMarginPx;
|
||||
private boolean visible;
|
||||
private boolean hidding;
|
||||
|
||||
public TrackDetailsMenu() {
|
||||
}
|
||||
private Location myLocation;
|
||||
|
||||
@Nullable
|
||||
public MapActivity getMapActivity() {
|
||||
|
@ -123,6 +125,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Location getMyLocation() {
|
||||
return myLocation;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
TrackDetailsMenuFragment fragment = getMenuFragment();
|
||||
if (fragment != null) {
|
||||
|
|
|
@ -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();
|
||||
|
@ -243,4 +274,4 @@ public class TrackDetailsMenuFragment extends BaseOsmAndFragment {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,7 +40,6 @@ 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;
|
||||
|
@ -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);
|
||||
|
@ -841,7 +849,7 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
|
|||
private void syncGpx(GPXFile gpxFile) {
|
||||
MapMarkersGroup group = view.getApplication().getMapMarkersHelper().getMarkersGroup(gpxFile);
|
||||
if (group != null) {
|
||||
mapMarkersHelper.runSynchronization(group);
|
||||
mapMarkersHelper.runSynchronization(group);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue