use smoothed altitude values to get more realistic elevation data (see #99) - v2 (needs testing)

master
y20k 2021-05-02 22:51:22 +02:00
parent 3fa589e21c
commit bb00e18312
No known key found for this signature in database
GPG Key ID: 824D4259F41FAFF6
5 changed files with 143 additions and 119 deletions

View File

@ -108,7 +108,7 @@ object Keys {
const val DEFAULT_ACCURACY: Float = 300f // in meters const val DEFAULT_ACCURACY: Float = 300f // in meters
const val DEFAULT_ALTITUDE: Double = 0.0 const val DEFAULT_ALTITUDE: Double = 0.0
const val DEFAULT_TIME: Long = 0L const val DEFAULT_TIME: Long = 0L
const val DEFAULT_ALTITUDE_SMOOTHING_VALUE: Int = 15 const val DEFAULT_ALTITUDE_SMOOTHING_VALUE: Int = 10
const val DEFAULT_THRESHOLD_LOCATION_ACCURACY: Int = 30 // 30 meters const val DEFAULT_THRESHOLD_LOCATION_ACCURACY: Int = 30 // 30 meters
const val DEFAULT_THRESHOLD_LOCATION_AGE: Long = 60000000000L // one minute in nanoseconds const val DEFAULT_THRESHOLD_LOCATION_AGE: Long = 60000000000L // one minute in nanoseconds
const val DEFAULT_THRESHOLD_DISTANCE: Float = 15f // 15 meters const val DEFAULT_THRESHOLD_DISTANCE: Float = 15f // 15 meters

View File

@ -61,7 +61,6 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
var useImperial: Boolean = false var useImperial: Boolean = false
var gpsOnly: Boolean = false var gpsOnly: Boolean = false
var accuracyMultiplier: Int = 1 var accuracyMultiplier: Int = 1
var altitudeSmoothingValue: Int = Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE
var currentBestLocation: Location = LocationHelper.getDefaultLocation() var currentBestLocation: Location = LocationHelper.getDefaultLocation()
var lastSave: Date = Keys.DEFAULT_DATE var lastSave: Date = Keys.DEFAULT_DATE
var stepCountOffset: Float = 0f var stepCountOffset: Float = 0f
@ -72,6 +71,7 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
var bound: Boolean = false var bound: Boolean = false
private val binder = LocalBinder() private val binder = LocalBinder()
private val handler: Handler = Handler() private val handler: Handler = Handler()
private var altitudeValues: SimpleMovingAverageQueue = SimpleMovingAverageQueue(Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE)
private lateinit var locationManager: LocationManager private lateinit var locationManager: LocationManager
private lateinit var sensorManager: SensorManager private lateinit var sensorManager: SensorManager
private lateinit var notificationManager: NotificationManager private lateinit var notificationManager: NotificationManager
@ -91,7 +91,7 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
gpsOnly = PreferencesHelper.loadGpsOnly(this) gpsOnly = PreferencesHelper.loadGpsOnly(this)
useImperial = PreferencesHelper.loadUseImperialUnits(this) useImperial = PreferencesHelper.loadUseImperialUnits(this)
accuracyMultiplier = PreferencesHelper.loadAccuracyMultiplier(this) accuracyMultiplier = PreferencesHelper.loadAccuracyMultiplier(this)
altitudeSmoothingValue = PreferencesHelper.loadAltitudeSmoothingValue(this)
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
sensorManager = this.getSystemService(Context.SENSOR_SERVICE) as SensorManager sensorManager = this.getSystemService(Context.SENSOR_SERVICE) as SensorManager
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@ -104,7 +104,10 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
currentBestLocation = LocationHelper.getLastKnownLocation(this) currentBestLocation = LocationHelper.getLastKnownLocation(this)
track = FileHelper.readTrack(this, FileHelper.getTempFileUri(this)) track = FileHelper.readTrack(this, FileHelper.getTempFileUri(this))
backgroundJob = Job() backgroundJob = Job()
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener) altitudeValues.capacity = PreferencesHelper.loadAltitudeSmoothingValue(this)
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(
sharedPreferenceChangeListener
)
} }
@ -114,7 +117,10 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
// SERVICE RESTART (via START_STICKY) // SERVICE RESTART (via START_STICKY)
if (intent == null) { if (intent == null) {
if (trackingState == Keys.STATE_TRACKING_ACTIVE) { if (trackingState == Keys.STATE_TRACKING_ACTIVE) {
LogHelper.w(TAG, "Trackbook has been killed by the operating system. Trying to resume recording.") LogHelper.w(
TAG,
"Trackbook has been killed by the operating system. Trying to resume recording."
)
resumeTracking() resumeTracking()
} }
// ACTION STOP // ACTION STOP
@ -175,7 +181,9 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
// remove notification // remove notification
stopForeground(true) stopForeground(true)
// stop listening for changes in shared preferences // stop listening for changes in shared preferences
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener) PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(
sharedPreferenceChangeListener
)
// stop receiving location updates // stop receiving location updates
removeGpsLocationListener() removeGpsLocationListener()
removeNetworkLocationListener() removeNetworkLocationListener()
@ -304,15 +312,25 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
override fun onProviderEnabled(provider: String) { override fun onProviderEnabled(provider: String) {
LogHelper.v(TAG, "onProviderEnabled $provider") LogHelper.v(TAG, "onProviderEnabled $provider")
when (provider) { when (provider) {
LocationManager.GPS_PROVIDER -> gpsProviderActive = LocationHelper.isGpsEnabled(locationManager) LocationManager.GPS_PROVIDER -> gpsProviderActive = LocationHelper.isGpsEnabled(
LocationManager.NETWORK_PROVIDER -> networkProviderActive = LocationHelper.isNetworkEnabled(locationManager) locationManager
)
LocationManager.NETWORK_PROVIDER -> networkProviderActive =
LocationHelper.isNetworkEnabled(
locationManager
)
} }
} }
override fun onProviderDisabled(provider: String) { override fun onProviderDisabled(provider: String) {
LogHelper.v(TAG, "onProviderDisabled $provider") LogHelper.v(TAG, "onProviderDisabled $provider")
when (provider) { when (provider) {
LocationManager.GPS_PROVIDER -> gpsProviderActive = LocationHelper.isGpsEnabled(locationManager) LocationManager.GPS_PROVIDER -> gpsProviderActive = LocationHelper.isGpsEnabled(
LocationManager.NETWORK_PROVIDER -> networkProviderActive = LocationHelper.isNetworkEnabled(locationManager) locationManager
)
LocationManager.NETWORK_PROVIDER -> networkProviderActive =
LocationHelper.isNetworkEnabled(
locationManager
)
} }
} }
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) { override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {
@ -330,13 +348,24 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
gpsProviderActive = LocationHelper.isGpsEnabled(locationManager) gpsProviderActive = LocationHelper.isGpsEnabled(locationManager)
if (gpsProviderActive) { if (gpsProviderActive) {
// check for location permission // check for location permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED) {
// adds GPS location listener // adds GPS location listener
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f,gpsLocationListener) locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
0,
0f,
gpsLocationListener
)
gpsLocationListenerRegistered = true gpsLocationListenerRegistered = true
LogHelper.v(TAG, "Added GPS location listener.") LogHelper.v(TAG, "Added GPS location listener.")
} else { } else {
LogHelper.w(TAG, "Unable to add GPS location listener. Location permission is not granted.") LogHelper.w(
TAG,
"Unable to add GPS location listener. Location permission is not granted."
)
} }
} else { } else {
LogHelper.w(TAG, "Unable to add GPS location listener.") LogHelper.w(TAG, "Unable to add GPS location listener.")
@ -355,19 +384,33 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
networkProviderActive = LocationHelper.isNetworkEnabled(locationManager) networkProviderActive = LocationHelper.isNetworkEnabled(locationManager)
if (networkProviderActive && !gpsOnly) { if (networkProviderActive && !gpsOnly) {
// check for location permission // check for location permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED) {
// adds Network location listener // adds Network location listener
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0f, networkLocationListener) locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
0,
0f,
networkLocationListener
)
networkLocationListenerRegistered = true networkLocationListenerRegistered = true
LogHelper.v(TAG, "Added Network location listener.") LogHelper.v(TAG, "Added Network location listener.")
} else { } else {
LogHelper.w(TAG, "Unable to add Network location listener. Location permission is not granted.") LogHelper.w(
TAG,
"Unable to add Network location listener. Location permission is not granted."
)
} }
} else { } else {
LogHelper.w(TAG, "Unable to add Network location listener.") LogHelper.w(TAG, "Unable to add Network location listener.")
} }
} else { } else {
LogHelper.v(TAG, "Skipping registration. Network location listener has already been added.") LogHelper.v(
TAG,
"Skipping registration. Network location listener has already been added."
)
} }
} }
@ -379,7 +422,10 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
gpsLocationListenerRegistered = false gpsLocationListenerRegistered = false
LogHelper.v(TAG, "Removed GPS location listener.") LogHelper.v(TAG, "Removed GPS location listener.")
} else { } else {
LogHelper.w(TAG, "Unable to remove GPS location listener. Location permission is needed.") LogHelper.w(
TAG,
"Unable to remove GPS location listener. Location permission is needed."
)
} }
} }
@ -391,14 +437,21 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
networkLocationListenerRegistered = false networkLocationListenerRegistered = false
LogHelper.v(TAG, "Removed Network location listener.") LogHelper.v(TAG, "Removed Network location listener.")
} else { } else {
LogHelper.w(TAG, "Unable to remove Network location listener. Location permission is needed.") LogHelper.w(
TAG,
"Unable to remove Network location listener. Location permission is needed."
)
} }
} }
/* Registers a step counter listener */ /* Registers a step counter listener */
private fun startStepCounter() { private fun startStepCounter() {
val stepCounterAvailable = sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER), SensorManager.SENSOR_DELAY_UI) val stepCounterAvailable = sensorManager.registerListener(
this, sensorManager.getDefaultSensor(
Sensor.TYPE_STEP_COUNTER
), SensorManager.SENSOR_DELAY_UI
)
if (!stepCounterAvailable) { if (!stepCounterAvailable) {
LogHelper.w(TAG, "Pedometer sensor not available.") LogHelper.w(TAG, "Pedometer sensor not available.")
track.stepCount = -1f track.stepCount = -1f
@ -408,7 +461,12 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
/* Displays / updates notification */ /* Displays / updates notification */
private fun displayNotification(): Notification { private fun displayNotification(): Notification {
val notification: Notification = notificationHelper.createNotification(trackingState, track.length, track.duration, useImperial) val notification: Notification = notificationHelper.createNotification(
trackingState,
track.length,
track.duration,
useImperial
)
notificationManager.notify(Keys.TRACKER_SERVICE_NOTIFICATION_ID, notification) notificationManager.notify(Keys.TRACKER_SERVICE_NOTIFICATION_ID, notification)
return notification return notification
} }
@ -459,25 +517,34 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
private val periodicTrackUpdate: Runnable = object : Runnable { private val periodicTrackUpdate: Runnable = object : Runnable {
override fun run() { override fun run() {
// add waypoint to track - step count is continuously updated in onSensorChanged // add waypoint to track - step count is continuously updated in onSensorChanged
val result: Pair<Track, Boolean> = TrackHelper.addWayPointToTrack(this@TrackerService, track, currentBestLocation, accuracyMultiplier, altitudeSmoothingValue, resumed) val result: Pair<Boolean, Track> = TrackHelper.addWayPointToTrack(track, currentBestLocation, accuracyMultiplier, resumed)
// get track from result // get results
track = result.first val successfullyAdded: Boolean = result.first
// check if waypoint was successfully added (= result.second) track = result.second
if (resumed && result.second) {
// reset resumed flag, if necessary
resumed = false
}
// check, if waypoint was added // check, if waypoint was added
if (result.second) { if (successfullyAdded) {
// reset resumed flag, if necessary // reset resumed flag, if necessary
if (resumed) { if (resumed) {
resumed = false resumed = false
} }
// store previous smoothed altitude
val previousAltitude: Double = altitudeValues.average
// put current altitude into queue
altitudeValues.add(currentBestLocation.altitude)
// get current smoothed altitude
val currentAltitude: Double = altitudeValues.average
// calculate and store elevation differences
track = LocationHelper.calculateElevationDifferences(currentAltitude, previousAltitude, track)
// save a temp track // save a temp track
val now: Date = GregorianCalendar.getInstance().time val now: Date = GregorianCalendar.getInstance().time
if (now.time - lastSave.time > Keys.SAVE_TEMP_TRACK_INTERVAL) { if (now.time - lastSave.time > Keys.SAVE_TEMP_TRACK_INTERVAL) {
lastSave = now lastSave = now
GlobalScope.launch { FileHelper.saveTempTrackSuspended(this@TrackerService, track) } GlobalScope.launch { FileHelper.saveTempTrackSuspended(
this@TrackerService,
track
) }
} }
} }
// update notification // update notification
@ -491,4 +558,21 @@ class TrackerService: Service(), CoroutineScope, SensorEventListener {
*/ */
/* Simple queue that evicts older elements and holds an average */
/* Credit: CircularQueue https://stackoverflow.com/a/51923797 */
class SimpleMovingAverageQueue(var capacity: Int) : LinkedList<Double>() {
private var sum: Double = 0.0
var average: Double = sum / capacity
override fun add(element: Double): Boolean {
if (this.size >= capacity) {
sum -= this.first
removeFirst()
} else {
sum += element
}
return super.add(element)
}
}
} }

View File

@ -22,6 +22,7 @@ import android.os.Parcelable
import androidx.annotation.Keep import androidx.annotation.Keep
import com.google.gson.annotations.Expose import com.google.gson.annotations.Expose
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import org.y20k.trackbook.helpers.LocationHelper
/* /*
@ -44,7 +45,7 @@ data class WayPoint(@Expose val provider: String,
constructor(location: Location) : this (location.provider, location.latitude, location.longitude, location. altitude, location.accuracy, location.time) constructor(location: Location) : this (location.provider, location.latitude, location.longitude, location. altitude, location.accuracy, location.time)
/* Constructor using Location plus distanceToStartingPoint and numberSatellites */ /* Constructor using Location plus distanceToStartingPoint and numberSatellites */
constructor(location: Location, distanceToStartingPoint: Float, numberSatellites: Int) : this (location.provider, location.latitude, location.longitude, location. altitude, location.accuracy, location.time, distanceToStartingPoint, numberSatellites) constructor(location: Location, distanceToStartingPoint: Float) : this (location.provider, location.latitude, location.longitude, location. altitude, location.accuracy, location.time, distanceToStartingPoint, LocationHelper.getNumberOfSatellites(location))
/* Converts WayPoint into Location */ /* Converts WayPoint into Location */
fun toLocation(): Location { fun toLocation(): Location {

View File

@ -22,11 +22,11 @@ import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.location.Location import android.location.Location
import android.location.LocationManager import android.location.LocationManager
import android.os.Bundle
import android.os.SystemClock import android.os.SystemClock
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import org.y20k.trackbook.Keys import org.y20k.trackbook.Keys
import org.y20k.trackbook.core.Track import org.y20k.trackbook.core.Track
import org.y20k.trackbook.core.WayPoint
import java.util.* import java.util.*
import kotlin.math.pow import kotlin.math.pow
@ -232,23 +232,17 @@ object LocationHelper {
/* Calculate elevation differences */ /* Calculate elevation differences */
fun calculateElevationDifferences(previousLocation: Location?, location: Location, track: Track, altitudeSmoothingValue: Int): Pair<Double, Double> { fun calculateElevationDifferences(currentAltitude: Double, previousAltitude: Double, track: Track): Track {
// store current values if (currentAltitude != Keys.DEFAULT_ALTITUDE || previousAltitude != Keys.DEFAULT_ALTITUDE) {
var positiveElevation: Double = track.positiveElevation val altitudeDifference: Double = currentAltitude - previousAltitude
var negativeElevation: Double = track.negativeElevation
if (previousLocation != null && location.altitude != Keys.DEFAULT_ALTITUDE) {
val locationAltitudeCorrected: Double = calculateCorrectedAltitude(location, track, altitudeSmoothingValue)
val previousLocationAltitudeCorrected: Double = calculateCorrectedAltitude(previousLocation, track, altitudeSmoothingValue)
// get elevation difference and sum it up
val altitudeDifference: Double = locationAltitudeCorrected - previousLocationAltitudeCorrected
if (altitudeDifference > 0) { if (altitudeDifference > 0) {
positiveElevation = track.positiveElevation + altitudeDifference // upwards movement track.positiveElevation += altitudeDifference // upwards movement
} }
if (altitudeDifference < 0) { if (altitudeDifference < 0) {
negativeElevation = track.negativeElevation + altitudeDifference // downwards movement track.negativeElevation += altitudeDifference // downwards movement
} }
} }
return Pair(positiveElevation, negativeElevation) return track
} }
@ -260,29 +254,17 @@ object LocationHelper {
} }
/* Calculate a moving average taking into account previously recorded altitude values */ /* Get number of satellites from Location extras */
private fun calculateCorrectedAltitude(location: Location, track: Track, altitudeSmoothingValue: Int): Double { fun getNumberOfSatellites(location: Location): Int {
// add location to track val numberOfSatellites: Int
track.wayPoints.add(WayPoint(location)) val extras: Bundle? = location.extras
// get size of track if (extras != null && extras.containsKey("satellites")) {
val trackSize: Int = track.wayPoints.size numberOfSatellites = extras.getInt("satellites", 0)
// skip calculation if less than two waypoints available
if (trackSize < 2) return location.altitude
// get number of locations to be used in calculating the moving average
val numberOfLocationsUsedForSmoothing: Int = if (trackSize < altitudeSmoothingValue) {
trackSize
} else { } else {
altitudeSmoothingValue numberOfSatellites = 0
} }
// add altitude values in range and calculate average return numberOfSatellites
val mostRecentWaypointIndex: Int = trackSize - 1
var altitudeSum: Double = 0.0
for (i in mostRecentWaypointIndex..(mostRecentWaypointIndex - numberOfLocationsUsedForSmoothing)) {
altitudeSum = altitudeSum + track.wayPoints[i].altitude
}
return altitudeSum / numberOfLocationsUsedForSmoothing
} }
} }

View File

@ -49,8 +49,8 @@ object TrackHelper {
/* Adds given locatiom as waypoint to track */ /* Adds given locatiom as waypoint to track */
fun addWayPointToTrack(context: Context, track: Track, location: Location, accuracyMultiplier: Int, altitudeSmoothingValue: Int, resumed: Boolean): Pair<Track, Boolean> { fun addWayPointToTrack(track: Track, location: Location, accuracyMultiplier: Int, resumed: Boolean): Pair<Boolean, Track> {
// get previous location // Step 1: Get previous location
val previousLocation: Location? val previousLocation: Location?
var numberOfWayPoints: Int = track.wayPoints.size var numberOfWayPoints: Int = track.wayPoints.size
@ -69,90 +69,47 @@ object TrackHelper {
previousLocation = track.wayPoints[numberOfWayPoints - 1].toLocation() previousLocation = track.wayPoints[numberOfWayPoints - 1].toLocation()
} }
// update duration // Step 2: Update duration
val now: Date = GregorianCalendar.getInstance().time val now: Date = GregorianCalendar.getInstance().time
val difference: Long = now.time - track.recordingStop.time val difference: Long = now.time - track.recordingStop.time
track.duration = track.duration + difference track.duration = track.duration + difference
track.recordingStop = now track.recordingStop = now
// add only if recent and accurate and different // Step 3: Add waypoint, ifrecent and accurate and different enough
val shouldBeAdded: Boolean = (LocationHelper.isRecentEnough(location) && val shouldBeAdded: Boolean = (LocationHelper.isRecentEnough(location) &&
LocationHelper.isAccurateEnough(location, Keys.DEFAULT_THRESHOLD_LOCATION_ACCURACY) && LocationHelper.isAccurateEnough(location, Keys.DEFAULT_THRESHOLD_LOCATION_ACCURACY) &&
LocationHelper.isDifferentEnough(previousLocation, location, accuracyMultiplier)) LocationHelper.isDifferentEnough(previousLocation, location, accuracyMultiplier))
// // Debugging for shouldBeAdded - remove for production
// val recentEnough: Boolean = LocationHelper.isRecentEnough(location)
// val accurateEnough: Boolean = LocationHelper.isAccurateEnough(location, locationAccuracyThreshold)
// val differentEnough: Boolean = LocationHelper.isDifferentEnough(previousLocation, location)
// val shouldBeAdded = recentEnough && accurateEnough && differentEnough
// if (!recentEnough && accurateEnough && differentEnough) { Toast.makeText(context, "Debug: Not recent enough", Toast.LENGTH_LONG).show() }
// else if (!accurateEnough && recentEnough && differentEnough) { Toast.makeText(context, "Debug: Not accurate enough", Toast.LENGTH_LONG).show() }
// else if (!differentEnough && recentEnough && accurateEnough) { Toast.makeText(context, "Debug: Not different enough", Toast.LENGTH_LONG).show() }
// else if (!recentEnough && !accurateEnough && differentEnough) { Toast.makeText(context, "Debug: Not recent and accurate enough", Toast.LENGTH_LONG).show() }
// else if (!recentEnough && !differentEnough && accurateEnough) { Toast.makeText(context, "Debug: Not recent and different enough", Toast.LENGTH_LONG).show() }
// else if (!accurateEnough && !differentEnough && recentEnough) { Toast.makeText(context, "Debug: Not accurate and different enough", Toast.LENGTH_LONG).show() }
// else { Toast.makeText(context, "Debug: bad location.", Toast.LENGTH_LONG).show() }
if (shouldBeAdded) { if (shouldBeAdded) {
// update distance (do not update if resumed -> we do not want to add values calculated during a recording pause) // Step 3.1: Update distance (do not update if resumed -> we do not want to add values calculated during a recording pause)
if (!resumed) { if (!resumed) {
track.length = track.length + LocationHelper.calculateDistance(previousLocation, location) track.length = track.length + LocationHelper.calculateDistance(previousLocation, location)
} }
// Step 3.2: Update altitude values
// update altitude values
val altitude: Double = location.altitude val altitude: Double = location.altitude
if (altitude != 0.0) { if (altitude != 0.0) {
// CASE: First location
if (numberOfWayPoints == 0) { if (numberOfWayPoints == 0) {
track.maxAltitude = altitude track.maxAltitude = altitude
track.minAltitude = altitude track.minAltitude = altitude
} }
// CASE: Not first location
else { else {
// Step 1: Update altitude values
if (altitude > track.maxAltitude) track.maxAltitude = altitude if (altitude > track.maxAltitude) track.maxAltitude = altitude
if (altitude < track.minAltitude) track.minAltitude = altitude if (altitude < track.minAltitude) track.minAltitude = altitude
// Step 2: Calculate and update elevation values (upwards / downwards movements)
val elevationDifferences: Pair<Double, Double> = LocationHelper.calculateElevationDifferences(previousLocation, location, track, altitudeSmoothingValue)
// check if any differences were calculated
if (elevationDifferences != Pair(track.positiveElevation, track.negativeElevation)) {
// update elevation values (do not update if resumed -> we do not want to add values calculated during a recording pause)
if (!resumed) {
track.positiveElevation = elevationDifferences.first
track.negativeElevation = elevationDifferences.second
}
}
} }
} }
// Step 3.3: Toggle stop over status, if necessary
// toggle stop over status, if necessary
if (track.wayPoints.size < 0) { if (track.wayPoints.size < 0) {
track.wayPoints[track.wayPoints.size - 1].isStopOver = LocationHelper.isStopOver(previousLocation, location) track.wayPoints[track.wayPoints.size - 1].isStopOver = LocationHelper.isStopOver(previousLocation, location)
} }
// save number of satellites // Step 3.4: Add current location as point to center on for later display
val numberSatellites: Int
val extras = location.extras
if (extras != null && extras.containsKey("satellites")) {
numberSatellites = extras.getInt("satellites", 0)
} else {
numberSatellites = 0
}
// add current location as point to center on for later display
track.latitude = location.latitude track.latitude = location.latitude
track.longitude = location.longitude track.longitude = location.longitude
// add location as new waypoint // Step 3.5: Add location as new waypoint
track.wayPoints.add(WayPoint(location, distanceToStartingPoint = track.length, numberSatellites = numberSatellites)) track.wayPoints.add(WayPoint(location = location, distanceToStartingPoint = track.length))
} }
return Pair(track, shouldBeAdded) return Pair(shouldBeAdded, track)
} }