long press on map recording zooms it to bounding box #60
This commit is contained in:
parent
1683dc64e0
commit
7402f872be
7 changed files with 156 additions and 107 deletions
|
@ -24,6 +24,8 @@ import android.content.IntentFilter;
|
|||
import android.location.Location;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Vibrator;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
@ -48,10 +50,12 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
|
||||
import org.osmdroid.api.IMapController;
|
||||
import org.osmdroid.events.MapEventsReceiver;
|
||||
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
|
||||
import org.osmdroid.util.GeoPoint;
|
||||
import org.osmdroid.views.MapView;
|
||||
import org.osmdroid.views.overlay.ItemizedIconOverlay;
|
||||
import org.osmdroid.views.overlay.MapEventsOverlay;
|
||||
import org.osmdroid.views.overlay.TilesOverlay;
|
||||
import org.osmdroid.views.overlay.compass.CompassOverlay;
|
||||
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider;
|
||||
|
@ -75,7 +79,7 @@ import java.util.Locale;
|
|||
/**
|
||||
* MainActivityTrackFragment class
|
||||
*/
|
||||
public class MainActivityTrackFragment extends Fragment implements AdapterView.OnItemSelectedListener, TrackbookKeys {
|
||||
public class MainActivityTrackFragment extends Fragment implements AdapterView.OnItemSelectedListener, MapEventsReceiver, TrackbookKeys {
|
||||
|
||||
/* Define log tag */
|
||||
private static final String LOG_TAG = MainActivityTrackFragment.class.getSimpleName();
|
||||
|
@ -268,6 +272,10 @@ public class MainActivityTrackFragment extends Fragment implements AdapterView.O
|
|||
attachTapListenerToStatisticsSheet();
|
||||
}
|
||||
|
||||
// enable additional gestures
|
||||
MapEventsOverlay OverlayEventos = new MapEventsOverlay(this);
|
||||
mMapView.getOverlays().add(OverlayEventos);
|
||||
|
||||
return mRootView;
|
||||
}
|
||||
|
||||
|
@ -365,6 +373,25 @@ public class MainActivityTrackFragment extends Fragment implements AdapterView.O
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean singleTapConfirmedHelper(GeoPoint p) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean longPressHelper(GeoPoint p) {
|
||||
if (mTrack != null) {
|
||||
// vibrate 50 milliseconds
|
||||
Vibrator vibrator = (Vibrator) mActivity.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
vibrator.vibrate(50);
|
||||
// zoom to bounding box (= edge coordinates of map)
|
||||
mMapView.zoomToBoundingBox(mTrack.getBoundingBox(), true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Displays map and statistics for track */
|
||||
private void displayTrack() {
|
||||
GeoPoint position;
|
||||
|
@ -405,7 +432,6 @@ public class MainActivityTrackFragment extends Fragment implements AdapterView.O
|
|||
|
||||
// draw track on map
|
||||
drawTrackOverlay(mTrack);
|
||||
|
||||
} else {
|
||||
position = new GeoPoint(DEFAULT_LATITUDE, DEFAULT_LONGITUDE);
|
||||
}
|
||||
|
|
|
@ -54,36 +54,11 @@ public class Track implements TrackbookKeys, Parcelable {
|
|||
private double mMinAltitude;
|
||||
private double mPositiveElevation;
|
||||
private double mNegativeElevation;
|
||||
private BoundingBox mBoundingBox;
|
||||
|
||||
private BoundingBox boundingBox;
|
||||
|
||||
/**
|
||||
* Create a {@code BoundingBox} for the collection of
|
||||
* {@code WayPoint}s, so that it would be possible to fit the map in
|
||||
* such box and see the whole {@code Track} in the map without
|
||||
* manual zooming.
|
||||
*
|
||||
* It computes the {@code BoundingBox} only once since it's possibly
|
||||
* useless to compute it everytime.
|
||||
*
|
||||
* @return {@code BoundingBox} containing all {@code Waypoint}s
|
||||
*/
|
||||
public BoundingBox getBoundingBox() {
|
||||
if (null == boundingBox) {
|
||||
final ArrayList<GeoPoint> geoPoints = new ArrayList<>(mWayPoints.size());
|
||||
|
||||
for (final WayPoint aWayPoint : mWayPoints) {
|
||||
final GeoPoint aGeoPoint = new GeoPoint(aWayPoint.getLocation());
|
||||
geoPoints.add(aGeoPoint);
|
||||
}
|
||||
|
||||
boundingBox = BoundingBox.fromGeoPoints(geoPoints);
|
||||
}
|
||||
return boundingBox;
|
||||
}
|
||||
|
||||
/* Generic Constructor */
|
||||
public Track(int trackFormatVersion, List<WayPoint> wayPoints, float trackLength, long duration, float stepCount, Date recordingStart, Date recordingStop, double maxAltitude, double minAltitude, double positiveElevation, double negativeElevation) {
|
||||
public Track(int trackFormatVersion, List<WayPoint> wayPoints, float trackLength, long duration, float stepCount, Date recordingStart, Date recordingStop, double maxAltitude, double minAltitude, double positiveElevation, double negativeElevation, BoundingBox boundingBox) {
|
||||
mTrackFormatVersion = trackFormatVersion;
|
||||
mWayPoints = wayPoints;
|
||||
mTrackLength = trackLength;
|
||||
|
@ -95,12 +70,13 @@ public class Track implements TrackbookKeys, Parcelable {
|
|||
mMinAltitude = minAltitude;
|
||||
mPositiveElevation = positiveElevation;
|
||||
mNegativeElevation = negativeElevation;
|
||||
mBoundingBox = boundingBox;
|
||||
}
|
||||
|
||||
|
||||
/* Copy Constructor */
|
||||
public Track(Track track) {
|
||||
this(track.getTrackFormatVersion(), track.getWayPoints(), track.getTrackLength(), track.getTrackDuration(), track.getStepCount(), track.getRecordingStart(), track.getRecordingStop(), track.getMaxAltitude(), track.getMinAltitude(), track.getPositiveElevation(), track.getNegativeElevation());
|
||||
this(track.getTrackFormatVersion(), track.getWayPoints(), track.getTrackLength(), track.getTrackDuration(), track.getStepCount(), track.getRecordingStart(), track.getRecordingStop(), track.getMaxAltitude(), track.getMinAltitude(), track.getPositiveElevation(), track.getNegativeElevation(), track.getBoundingBox());
|
||||
}
|
||||
|
||||
|
||||
|
@ -117,6 +93,7 @@ public class Track implements TrackbookKeys, Parcelable {
|
|||
mMinAltitude = 0f;
|
||||
mPositiveElevation = 0f;
|
||||
mNegativeElevation = 0f;
|
||||
mBoundingBox = new BoundingBox();
|
||||
}
|
||||
|
||||
|
||||
|
@ -231,6 +208,12 @@ public class Track implements TrackbookKeys, Parcelable {
|
|||
}
|
||||
|
||||
|
||||
/* Setter for this track's BoundingBox - a data structure describing the edge coordinates of a track */
|
||||
public void setBoundingBox(BoundingBox boundingBox) {
|
||||
mBoundingBox = boundingBox;
|
||||
}
|
||||
|
||||
|
||||
/* Getter for file/track format version */
|
||||
public int getTrackFormatVersion() {
|
||||
return mTrackFormatVersion;
|
||||
|
@ -302,6 +285,10 @@ public class Track implements TrackbookKeys, Parcelable {
|
|||
}
|
||||
|
||||
|
||||
/* Getter for this track's BoundingBox - a data structure describing the edge coordinates of a track */
|
||||
public BoundingBox getBoundingBox() { return mBoundingBox; }
|
||||
|
||||
|
||||
/* Getter recorded distance */
|
||||
public Double getTrackDistance() {
|
||||
int size = mWayPoints.size();
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
|
||||
package org.y20k.trackbook.core;
|
||||
|
||||
import org.osmdroid.util.BoundingBox;
|
||||
import org.y20k.trackbook.helpers.LogHelper;
|
||||
import org.y20k.trackbook.helpers.MapHelper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -44,10 +46,11 @@ public class TrackBuilder {
|
|||
private final double mMinAltitude;
|
||||
private final double mPositiveElevation;
|
||||
private final double mNegativeElevation;
|
||||
private BoundingBox mBoundingBox;
|
||||
|
||||
|
||||
/* Generic Constructor */
|
||||
public TrackBuilder(int trackFormatVersion, List<WayPoint> wayPoints, float trackLength, long duration, float stepCount, Date recordingStart, Date recordingStop, double maxAltitude, double minAltitude, double positiveElevation, double negativeElevation) {
|
||||
public TrackBuilder(int trackFormatVersion, List<WayPoint> wayPoints, float trackLength, long duration, float stepCount, Date recordingStart, Date recordingStop, double maxAltitude, double minAltitude, double positiveElevation, double negativeElevation, BoundingBox boundingBox) {
|
||||
mTrackFormatVersion = trackFormatVersion;
|
||||
mWayPoints = wayPoints;
|
||||
mTrackLength = trackLength;
|
||||
|
@ -59,6 +62,7 @@ public class TrackBuilder {
|
|||
mMinAltitude = minAltitude;
|
||||
mPositiveElevation = positiveElevation;
|
||||
mNegativeElevation = negativeElevation;
|
||||
mBoundingBox = boundingBox;
|
||||
}
|
||||
|
||||
|
||||
|
@ -67,10 +71,13 @@ public class TrackBuilder {
|
|||
switch (mTrackFormatVersion) {
|
||||
case 1:
|
||||
// file format version 1 - does not have elevation data stored
|
||||
return new Track(mTrackFormatVersion, mWayPoints, mTrackLength, mDuration, mStepCount, mRecordingStart, mRecordingStop, 0f, 0f, 0f, 0f);
|
||||
return new Track(mTrackFormatVersion, mWayPoints, mTrackLength, mDuration, mStepCount, mRecordingStart, mRecordingStop, 0f, 0f, 0f, 0f, new BoundingBox());
|
||||
case 2:
|
||||
// file format version 2 (current version)
|
||||
return new Track(mTrackFormatVersion, mWayPoints, mTrackLength, mDuration, mStepCount, mRecordingStart, mRecordingStop, mMaxAltitude, mMinAltitude, mPositiveElevation, mNegativeElevation);
|
||||
// file format version 2 - does not have edge coordinates stored
|
||||
return new Track(mTrackFormatVersion, mWayPoints, mTrackLength, mDuration, mStepCount, mRecordingStart, mRecordingStop, mMaxAltitude, mMinAltitude, mPositiveElevation, mNegativeElevation, MapHelper.calculateBoundingBox(mWayPoints));
|
||||
case 3:
|
||||
// file format version 3 (current version)
|
||||
return new Track(mTrackFormatVersion, mWayPoints, mTrackLength, mDuration, mStepCount, mRecordingStart, mRecordingStop, mMaxAltitude, mMinAltitude, mPositiveElevation, mNegativeElevation, new BoundingBox());
|
||||
default:
|
||||
LogHelper.e(LOG_TAG, "Unknown file format version: " + mTrackFormatVersion);
|
||||
return null;
|
||||
|
|
|
@ -21,6 +21,7 @@ import android.graphics.drawable.Drawable;
|
|||
import android.location.Location;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.osmdroid.util.BoundingBox;
|
||||
import org.osmdroid.util.GeoPoint;
|
||||
import org.osmdroid.views.overlay.ItemizedIconOverlay;
|
||||
import org.osmdroid.views.overlay.OverlayItem;
|
||||
|
@ -33,12 +34,14 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
|
||||
/**
|
||||
* MapHelper class
|
||||
*/
|
||||
public final class MapHelper {
|
||||
public final class MapHelper implements TrackbookKeys {
|
||||
|
||||
/* Define log tag */
|
||||
private static final String LOG_TAG = MapHelper.class.getSimpleName();
|
||||
|
@ -181,4 +184,92 @@ public final class MapHelper {
|
|||
return new OverlayItem(title, description, position);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@code BoundingBox} for the collection of
|
||||
* {@code WayPoint}s, so that it would be possible to fit the map in
|
||||
* such box and see the whole {@code Track} in the map without
|
||||
* manual zooming.
|
||||
*
|
||||
* @return {@code BoundingBox} containing all {@code Waypoint}s
|
||||
*/
|
||||
public static BoundingBox calculateBoundingBox(List<WayPoint> wayPoints) {
|
||||
final ArrayList<GeoPoint> geoPoints = new ArrayList<>(wayPoints.size());
|
||||
|
||||
for (final WayPoint aWayPoint : wayPoints) {
|
||||
final GeoPoint aGeoPoint = new GeoPoint(aWayPoint.getLocation());
|
||||
geoPoints.add(aGeoPoint);
|
||||
}
|
||||
return BoundingBox.fromGeoPoints(geoPoints);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Calculates positive and negative elevation of track */
|
||||
public static Track calculateElevation(@Nullable Track track) {
|
||||
double maxAltitude = 0;
|
||||
double minAltitude = 0;
|
||||
double positiveElevation = 0;
|
||||
double negativeElevation = 0;
|
||||
|
||||
if (track != null && track.getWayPoints().size() > 0) {
|
||||
double previousLocationAltitude;
|
||||
double currentLocationAltitude;
|
||||
long previousTimeStamp;
|
||||
long currentTimeStamp;
|
||||
|
||||
// initial values for max height and min height - first waypoint
|
||||
maxAltitude = track.getWayPointLocation(0).getAltitude();
|
||||
minAltitude = maxAltitude;
|
||||
|
||||
// apply filter & smooth data
|
||||
// track = smoothTrack(track, 15f, 35f);
|
||||
|
||||
// iterate over track
|
||||
for (int i = 1; i < track.getWayPoints().size(); i++ ) {
|
||||
|
||||
// get time difference
|
||||
previousTimeStamp = track.getWayPointLocation(i -1).getTime();
|
||||
currentTimeStamp = track.getWayPointLocation(i).getTime();
|
||||
double timeDiff = (currentTimeStamp - previousTimeStamp);
|
||||
|
||||
// factor is bigger than 1 if the time stamp difference is larger than the movement recording interval (usually 15 seconds)
|
||||
double timeDiffFactor = timeDiff / FIFTEEN_SECONDS_IN_MILLISECONDS;
|
||||
|
||||
// height of previous and current waypoints
|
||||
previousLocationAltitude = track.getWayPointLocation(i -1).getAltitude();
|
||||
currentLocationAltitude = track.getWayPointLocation(i).getAltitude();
|
||||
|
||||
// check for new min and max heights
|
||||
if (currentLocationAltitude > maxAltitude) {
|
||||
maxAltitude = currentLocationAltitude;
|
||||
}
|
||||
if (minAltitude == 0 || currentLocationAltitude < minAltitude) {
|
||||
minAltitude = currentLocationAltitude;
|
||||
}
|
||||
|
||||
// get elevation difference and sum it up
|
||||
double altitudeDiff = currentLocationAltitude - previousLocationAltitude;
|
||||
if (altitudeDiff > 0 && altitudeDiff < MEASUREMENT_ERROR_THRESHOLD * timeDiffFactor && currentLocationAltitude != 0) {
|
||||
positiveElevation = positiveElevation + altitudeDiff;
|
||||
}
|
||||
if (altitudeDiff < 0 && altitudeDiff > -MEASUREMENT_ERROR_THRESHOLD * timeDiffFactor && currentLocationAltitude != 0) {
|
||||
negativeElevation = negativeElevation + altitudeDiff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// store elevation data in track
|
||||
track.setMaxAltitude(maxAltitude);
|
||||
track.setMinAltitude(minAltitude);
|
||||
track.setPositiveElevation(positiveElevation);
|
||||
track.setNegativeElevation(negativeElevation);
|
||||
}
|
||||
return track;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -103,18 +103,20 @@ public class StorageHelper implements TrackbookKeys {
|
|||
}
|
||||
|
||||
if (mFolder != null && mFolder.exists() && mFolder.isDirectory() && mFolder.canWrite() && recordingStart != null && track != null) {
|
||||
// calculate elevation and store it in track
|
||||
track = calculateElevation(track);
|
||||
|
||||
// create file object
|
||||
// create file object and calculate bounding box and elevation, if necessary
|
||||
String fileName;
|
||||
if (fileType == FILE_TEMP_TRACK) {
|
||||
// case: temp file
|
||||
// get the temp file name
|
||||
fileName = FILE_NAME_TEMP + FILE_TYPE_TRACKBOOK_EXTENSION;
|
||||
} else {
|
||||
// case: regular file
|
||||
// build a regular file name
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US);
|
||||
fileName = dateFormat.format(recordingStart) + FILE_TYPE_TRACKBOOK_EXTENSION;
|
||||
// calculate elevation and store it in track
|
||||
track = MapHelper.calculateElevation(track);
|
||||
// calculate bounding box and store it in track
|
||||
track.setBoundingBox(MapHelper.calculateBoundingBox(track.getWayPoints()));
|
||||
}
|
||||
File file = new File(mFolder.toString() + "/" + fileName);
|
||||
|
||||
|
@ -360,70 +362,6 @@ public class StorageHelper implements TrackbookKeys {
|
|||
}
|
||||
|
||||
|
||||
/* Calculates positive and negative elevation of track */
|
||||
private Track calculateElevation(@Nullable Track track) {
|
||||
double maxAltitude = 0;
|
||||
double minAltitude = 0;
|
||||
double positiveElevation = 0;
|
||||
double negativeElevation = 0;
|
||||
|
||||
if (track != null && track.getWayPoints().size() > 0) {
|
||||
double previousLocationAltitude;
|
||||
double currentLocationAltitude;
|
||||
long previousTimeStamp;
|
||||
long currentTimeStamp;
|
||||
|
||||
// initial values for max height and min height - first waypoint
|
||||
maxAltitude = track.getWayPointLocation(0).getAltitude();
|
||||
minAltitude = maxAltitude;
|
||||
|
||||
// apply filter & smooth data
|
||||
// track = smoothTrack(track, 15f, 35f);
|
||||
|
||||
// iterate over track
|
||||
for (int i = 1; i < track.getWayPoints().size(); i++ ) {
|
||||
|
||||
// get time difference
|
||||
previousTimeStamp = track.getWayPointLocation(i -1).getTime();
|
||||
currentTimeStamp = track.getWayPointLocation(i).getTime();
|
||||
double timeDiff = (currentTimeStamp - previousTimeStamp);
|
||||
|
||||
// factor is bigger than 1 if the time stamp difference is larger than the movement recording interval (usually 15 seconds)
|
||||
double timeDiffFactor = timeDiff / FIFTEEN_SECONDS_IN_MILLISECONDS;
|
||||
|
||||
// height of previous and current waypoints
|
||||
previousLocationAltitude = track.getWayPointLocation(i -1).getAltitude();
|
||||
currentLocationAltitude = track.getWayPointLocation(i).getAltitude();
|
||||
|
||||
// check for new min and max heights
|
||||
if (currentLocationAltitude > maxAltitude) {
|
||||
maxAltitude = currentLocationAltitude;
|
||||
}
|
||||
if (minAltitude == 0 || currentLocationAltitude < minAltitude) {
|
||||
minAltitude = currentLocationAltitude;
|
||||
}
|
||||
|
||||
// get elevation difference and sum it up
|
||||
double altitudeDiff = currentLocationAltitude - previousLocationAltitude;
|
||||
if (altitudeDiff > 0 && altitudeDiff < MEASUREMENT_ERROR_THRESHOLD * timeDiffFactor && currentLocationAltitude != 0) {
|
||||
positiveElevation = positiveElevation + altitudeDiff;
|
||||
}
|
||||
if (altitudeDiff < 0 && altitudeDiff > -MEASUREMENT_ERROR_THRESHOLD * timeDiffFactor && currentLocationAltitude != 0) {
|
||||
negativeElevation = negativeElevation + altitudeDiff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// store elevation data in track
|
||||
track.setMaxAltitude(maxAltitude);
|
||||
track.setMinAltitude(minAltitude);
|
||||
track.setPositiveElevation(positiveElevation);
|
||||
track.setNegativeElevation(negativeElevation);
|
||||
}
|
||||
return track;
|
||||
}
|
||||
|
||||
|
||||
/* Tries to smooth the elevation data using a low pass filter */
|
||||
private Track smoothTrack(Track input, float dt, float rc) {
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ public interface TrackbookKeys {
|
|||
String NOTIFICATION_CHANEL_ID_RECORDING_CHANNEL ="notificationChannelIdRecordingChannel";
|
||||
|
||||
/* MISC */
|
||||
int CURRENT_TRACK_FORMAT_VERSION = 2; // incremental version number to prevent issues in case the Track format evolves
|
||||
int CURRENT_TRACK_FORMAT_VERSION = 3; // incremental version number to prevent issues in case the Track format evolves
|
||||
double DEFAULT_LATITUDE = 71.172500; // latitude Nordkapp, Norway
|
||||
double DEFAULT_LONGITUDE = 25.784444; // longitude Nordkapp, Norway
|
||||
int MEASUREMENT_ERROR_THRESHOLD = 10; // altitude changes of 10 meter or more (per 15 seconds) are being discarded
|
||||
|
|
|
@ -24,8 +24,8 @@ allprojects {
|
|||
|
||||
project.ext {
|
||||
applicationId = 'org.y20k.trackbook'
|
||||
versionCode = 36
|
||||
versionName = '1.2.2'
|
||||
versionCode = 37
|
||||
versionName = '1.2.3'
|
||||
|
||||
compileSdkVersion = 28
|
||||
targetSdkVersion = 27
|
||||
|
|
Loading…
Reference in a new issue