mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 17:43:06 +02:00
Making Track and Waypoint use the TripStatisticsData class.
This grealy simplifies those classes since the fields are the same. There's certainly more cleanup to do on top of this, but I thought this was already more than enough for a single change. The only *functional* change expected from this is that the average speed is now calculated over the time until the last known position, which IMHO makes sense since the distance used in that calculation only includes up to that position. The visible effect is that having no GPS signal doesn't make the speed decrease. This was imported from perforce CL 15953263.
This commit is contained in:
@@ -22,7 +22,7 @@ import com.google.android.apps.mytracks.content.TrackPointsColumns;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||
import com.google.android.apps.mytracks.util.MyTracksUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -488,10 +488,10 @@ public class ChartActivity extends Activity implements
|
||||
if (Math.abs(location.getSpeed() - 128) > 1) {
|
||||
speedBuffer.setNext(location.getSpeed());
|
||||
}
|
||||
} else if (TripStatistics.isValidSpeed(
|
||||
} else if (TripStatisticsBuilder.isValidSpeed(
|
||||
location.getTime(), location.getSpeed(), lastLocation.getTime(),
|
||||
lastLocation.getSpeed(), speedBuffer)
|
||||
&& (location.getSpeed() <= track.getMaxSpeed())) {
|
||||
&& (location.getSpeed() <= track.getStatistics().getMaxSpeed())) {
|
||||
speedBuffer.setNext(location.getSpeed());
|
||||
}
|
||||
result[2] = speedBuffer.getAverage() * 3.6;
|
||||
|
||||
Executable → Regular
Executable → Regular
+6
-4
@@ -21,6 +21,7 @@ import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TrackPointsColumns;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.MyTracksUtils;
|
||||
import com.google.android.maps.GeoPoint;
|
||||
import com.google.android.maps.MapActivity;
|
||||
@@ -657,14 +658,15 @@ public class MyTracksMap extends MapActivity
|
||||
if (track == null || mapView == null || track.getNumberOfPoints() < 2) {
|
||||
return;
|
||||
}
|
||||
int latSpanE6 = track.getTop() - track.getBottom();
|
||||
int lonSpanE6 = track.getRight() - track.getLeft();
|
||||
TripStatistics stats = track.getStatistics();
|
||||
int latSpanE6 = stats.getTop() - stats.getBottom();
|
||||
int lonSpanE6 = stats.getRight() - stats.getLeft();
|
||||
if (latSpanE6 > 0 && latSpanE6 < 180E6 && lonSpanE6 > 0
|
||||
&& lonSpanE6 < 180E6) {
|
||||
keepMyLocationVisible = false;
|
||||
GeoPoint center = new GeoPoint(
|
||||
track.getBottom() + latSpanE6 / 2,
|
||||
track.getLeft() + lonSpanE6 / 2);
|
||||
stats.getBottom() + latSpanE6 / 2,
|
||||
stats.getLeft() + lonSpanE6 / 2);
|
||||
if (MyTracksUtils.isValidGeoPoint(center)) {
|
||||
mapView.getController().setCenter(center);
|
||||
mapView.getController().zoomToSpan(latSpanE6, lonSpanE6);
|
||||
|
||||
Executable → Regular
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Activity;
|
||||
@@ -132,8 +133,9 @@ public class MyTracksWaypointDetails extends Activity
|
||||
detailsView.setVisibility(View.GONE);
|
||||
statsView.setVisibility(View.VISIBLE);
|
||||
iconId = R.drawable.ylw_pushpin;
|
||||
utils.setAllStats(waypoint);
|
||||
utils.setTime(R.id.total_time_register, waypoint.getTotalTime());
|
||||
TripStatistics waypointStats = waypoint.getStatistics();
|
||||
utils.setAllStats(waypointStats);
|
||||
utils.setTime(R.id.total_time_register, waypointStats.getTotalTime());
|
||||
utils.setAltitude(
|
||||
R.id.elevation_register, waypoint.getLocation().getAltitude());
|
||||
break;
|
||||
|
||||
@@ -168,16 +168,20 @@ public class MyTracksWaypointsList extends ListActivity
|
||||
switch (v.getId()) {
|
||||
case R.id.waypointslist_btn_insert_waypoint: {
|
||||
long id = MyTracks.getInstance().insertWaypointMarker();
|
||||
Intent intent = new Intent(this, MyTracksWaypointDetails.class);
|
||||
intent.putExtra("waypointid", id);
|
||||
startActivity(intent);
|
||||
if (id >= 0) {
|
||||
Intent intent = new Intent(this, MyTracksWaypointDetails.class);
|
||||
intent.putExtra("waypointid", id);
|
||||
startActivity(intent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case R.id.waypointslist_btn_insert_statistics: {
|
||||
long id = MyTracks.getInstance().insertStatisticsMarker();
|
||||
Intent intent = new Intent(this, MyTracksWaypointDetails.class);
|
||||
intent.putExtra("waypointid", id);
|
||||
startActivity(intent);
|
||||
if (id >= 0) {
|
||||
Intent intent = new Intent(this, MyTracksWaypointDetails.class);
|
||||
intent.putExtra("waypointid", id);
|
||||
startActivity(intent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -219,32 +218,18 @@ public class StatsUtilities {
|
||||
setGrade(R.id.max_grade_register, maxGrade);
|
||||
}
|
||||
|
||||
public void setAllStats(Waypoint wpt) {
|
||||
setTime(R.id.moving_time_register, wpt.getMovingTime());
|
||||
setDistance(R.id.total_distance_register, wpt.getTotalDistance() / 1000);
|
||||
setSpeed(R.id.average_speed_register, wpt.getAverageSpeed() * 3.6);
|
||||
public void setAllStats(TripStatistics stats) {
|
||||
setTime(R.id.moving_time_register, stats.getMovingTime());
|
||||
setDistance(R.id.total_distance_register, stats.getTotalDistance() / 1000);
|
||||
setSpeed(R.id.average_speed_register, stats.getAverageSpeed() * 3.6);
|
||||
setSpeed(R.id.average_moving_speed_register,
|
||||
wpt.getAverageMovingSpeed() * 3.6);
|
||||
setSpeed(R.id.max_speed_register, wpt.getMaxSpeed() * 3.6);
|
||||
setAltitude(R.id.min_elevation_register, wpt.getMinElevation());
|
||||
setAltitude(R.id.max_elevation_register, wpt.getMaxElevation());
|
||||
setAltitude(R.id.elevation_gain_register, wpt.getTotalElevationGain());
|
||||
setGrade(R.id.min_grade_register, wpt.getMinGrade());
|
||||
setGrade(R.id.max_grade_register, wpt.getMaxGrade());
|
||||
}
|
||||
|
||||
public void setAllStats(Track track) {
|
||||
setTime(R.id.moving_time_register, track.getMovingTime());
|
||||
setDistance(R.id.total_distance_register, track.getTotalDistance() / 1000);
|
||||
setSpeed(R.id.average_speed_register, track.getAverageSpeed() * 3.6);
|
||||
setSpeed(R.id.average_moving_speed_register,
|
||||
track.getAverageMovingSpeed() * 3.6);
|
||||
setSpeed(R.id.max_speed_register, track.getMaxSpeed() * 3.6);
|
||||
setAltitude(R.id.min_elevation_register, track.getMinElevation());
|
||||
setAltitude(R.id.max_elevation_register, track.getMaxElevation());
|
||||
setAltitude(R.id.elevation_gain_register, track.getTotalElevationGain());
|
||||
setGrade(R.id.min_grade_register, track.getMinGrade());
|
||||
setGrade(R.id.max_grade_register, track.getMaxGrade());
|
||||
stats.getAverageMovingSpeed() * 3.6);
|
||||
setSpeed(R.id.max_speed_register, stats.getMaxSpeed() * 3.6);
|
||||
setAltitude(R.id.min_elevation_register, stats.getMinElevation());
|
||||
setAltitude(R.id.max_elevation_register, stats.getMaxElevation());
|
||||
setAltitude(R.id.elevation_gain_register, stats.getTotalElevationGain());
|
||||
setGrade(R.id.min_grade_register, stats.getMinGrade());
|
||||
setGrade(R.id.max_grade_register, stats.getMaxGrade());
|
||||
}
|
||||
|
||||
public void setSpeedLabel(int id, int speedString, int paceString) {
|
||||
|
||||
+61
-73
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
@@ -82,6 +84,8 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
*/
|
||||
private static ContentValues createContentValues(Track track) {
|
||||
ContentValues values = new ContentValues();
|
||||
TripStatistics stats = track.getStatistics();
|
||||
|
||||
// Values id < 0 indicate no id is available:
|
||||
if (track.getId() >= 0) {
|
||||
values.put(TracksColumns._ID, track.getId());
|
||||
@@ -92,29 +96,31 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
values.put(TracksColumns.CATEGORY, track.getCategory());
|
||||
values.put(TracksColumns.NUMPOINTS, track.getNumberOfPoints());
|
||||
values.put(TracksColumns.STARTID, track.getStartId());
|
||||
values.put(TracksColumns.STARTTIME, track.getStartTime());
|
||||
values.put(TracksColumns.STOPTIME, track.getStopTime());
|
||||
values.put(TracksColumns.STARTTIME, stats.getStartTime());
|
||||
values.put(TracksColumns.STOPTIME, stats.getStopTime());
|
||||
values.put(TracksColumns.STOPID, track.getStopId());
|
||||
values.put(TracksColumns.TOTALDISTANCE, track.getTotalDistance());
|
||||
values.put(TracksColumns.TOTALTIME, track.getTotalTime());
|
||||
values.put(TracksColumns.MOVINGTIME, track.getMovingTime());
|
||||
values.put(TracksColumns.MAXLAT, track.getTop());
|
||||
values.put(TracksColumns.MINLAT, track.getBottom());
|
||||
values.put(TracksColumns.MAXLON, track.getRight());
|
||||
values.put(TracksColumns.MINLON, track.getLeft());
|
||||
values.put(TracksColumns.AVGSPEED, track.getAverageSpeed());
|
||||
values.put(TracksColumns.AVGMOVINGSPEED, track.getAverageMovingSpeed());
|
||||
values.put(TracksColumns.MAXSPEED, track.getMaxSpeed());
|
||||
values.put(TracksColumns.MINELEVATION, track.getMinElevation());
|
||||
values.put(TracksColumns.MAXELEVATION, track.getMaxElevation());
|
||||
values.put(TracksColumns.ELEVATIONGAIN, track.getTotalElevationGain());
|
||||
values.put(TracksColumns.MINGRADE, track.getMinGrade());
|
||||
values.put(TracksColumns.MAXGRADE, track.getMaxGrade());
|
||||
values.put(TracksColumns.TOTALDISTANCE, stats.getTotalDistance());
|
||||
values.put(TracksColumns.TOTALTIME, stats.getTotalTime());
|
||||
values.put(TracksColumns.MOVINGTIME, stats.getMovingTime());
|
||||
values.put(TracksColumns.MAXLAT, stats.getTop());
|
||||
values.put(TracksColumns.MINLAT, stats.getBottom());
|
||||
values.put(TracksColumns.MAXLON, stats.getRight());
|
||||
values.put(TracksColumns.MINLON, stats.getLeft());
|
||||
values.put(TracksColumns.AVGSPEED, stats.getAverageSpeed());
|
||||
values.put(TracksColumns.AVGMOVINGSPEED, stats.getAverageMovingSpeed());
|
||||
values.put(TracksColumns.MAXSPEED, stats.getMaxSpeed());
|
||||
values.put(TracksColumns.MINELEVATION, stats.getMinElevation());
|
||||
values.put(TracksColumns.MAXELEVATION, stats.getMaxElevation());
|
||||
values.put(TracksColumns.ELEVATIONGAIN, stats.getTotalElevationGain());
|
||||
values.put(TracksColumns.MINGRADE, stats.getMinGrade());
|
||||
values.put(TracksColumns.MAXGRADE, stats.getMaxGrade());
|
||||
return values;
|
||||
}
|
||||
|
||||
private static ContentValues createContentValues(Waypoint waypoint) {
|
||||
ContentValues values = new ContentValues();
|
||||
TripStatistics stats = waypoint.getStatistics();
|
||||
|
||||
// Values id < 0 indicate no id is available:
|
||||
if (waypoint.getId() >= 0) {
|
||||
values.put(WaypointsColumns._ID, waypoint.getId());
|
||||
@@ -127,23 +133,21 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
values.put(WaypointsColumns.TYPE, waypoint.getType());
|
||||
values.put(WaypointsColumns.LENGTH, waypoint.getLength());
|
||||
values.put(WaypointsColumns.DURATION, waypoint.getDuration());
|
||||
values.put(WaypointsColumns.STARTTIME, waypoint.getStartTime());
|
||||
values.put(WaypointsColumns.STARTTIME, stats.getStartTime());
|
||||
values.put(WaypointsColumns.STARTID, waypoint.getStartId());
|
||||
values.put(WaypointsColumns.STOPID, waypoint.getStopId());
|
||||
|
||||
values.put(WaypointsColumns.TOTALDISTANCE, waypoint.getTotalDistance());
|
||||
values.put(WaypointsColumns.TOTALTIME, waypoint.getTotalTime());
|
||||
values.put(WaypointsColumns.MOVINGTIME, waypoint.getMovingTime());
|
||||
values.put(WaypointsColumns.AVGSPEED, waypoint.getAverageSpeed());
|
||||
values.put(WaypointsColumns.AVGMOVINGSPEED,
|
||||
waypoint.getAverageMovingSpeed());
|
||||
values.put(WaypointsColumns.MAXSPEED, waypoint.getMaxSpeed());
|
||||
values.put(WaypointsColumns.MINELEVATION, waypoint.getMinElevation());
|
||||
values.put(WaypointsColumns.MAXELEVATION, waypoint.getMaxElevation());
|
||||
values.put(WaypointsColumns.ELEVATIONGAIN,
|
||||
waypoint.getTotalElevationGain());
|
||||
values.put(WaypointsColumns.MINGRADE, waypoint.getMinGrade());
|
||||
values.put(WaypointsColumns.MAXGRADE, waypoint.getMaxGrade());
|
||||
values.put(WaypointsColumns.TOTALDISTANCE, stats.getTotalDistance());
|
||||
values.put(WaypointsColumns.TOTALTIME, stats.getTotalTime());
|
||||
values.put(WaypointsColumns.MOVINGTIME, stats.getMovingTime());
|
||||
values.put(WaypointsColumns.AVGSPEED, stats.getAverageSpeed());
|
||||
values.put(WaypointsColumns.AVGMOVINGSPEED, stats.getAverageMovingSpeed());
|
||||
values.put(WaypointsColumns.MAXSPEED, stats.getMaxSpeed());
|
||||
values.put(WaypointsColumns.MINELEVATION, stats.getMinElevation());
|
||||
values.put(WaypointsColumns.MAXELEVATION, stats.getMaxElevation());
|
||||
values.put(WaypointsColumns.ELEVATIONGAIN, stats.getTotalElevationGain());
|
||||
values.put(WaypointsColumns.MINGRADE, stats.getMinGrade());
|
||||
values.put(WaypointsColumns.MAXGRADE, stats.getMaxGrade());
|
||||
|
||||
Location location = waypoint.getLocation();
|
||||
if (location != null) {
|
||||
@@ -232,9 +236,6 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
cursor.getColumnIndexOrThrow(TracksColumns.TOTALDISTANCE);
|
||||
int idxTotalTime = cursor.getColumnIndexOrThrow(TracksColumns.TOTALTIME);
|
||||
int idxMovingTime = cursor.getColumnIndexOrThrow(TracksColumns.MOVINGTIME);
|
||||
int idxAverageSpeed = cursor.getColumnIndexOrThrow(TracksColumns.AVGSPEED);
|
||||
int idxAverageMovingSpeed =
|
||||
cursor.getColumnIndexOrThrow(TracksColumns.AVGMOVINGSPEED);
|
||||
int idxMaxSpeed = cursor.getColumnIndexOrThrow(TracksColumns.MAXSPEED);
|
||||
int idxMinElevation =
|
||||
cursor.getColumnIndexOrThrow(TracksColumns.MINELEVATION);
|
||||
@@ -246,6 +247,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
int idxMaxGrade = cursor.getColumnIndexOrThrow(TracksColumns.MAXGRADE);
|
||||
|
||||
Track track = new Track();
|
||||
TripStatistics stats = track.getStatistics();
|
||||
if (!cursor.isNull(idxId)) {
|
||||
track.setId(cursor.getLong(idxId));
|
||||
}
|
||||
@@ -265,10 +267,10 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
track.setStartId(cursor.getInt(idxStartId));
|
||||
}
|
||||
if (!cursor.isNull(idxStartTime)) {
|
||||
track.setStartTime(cursor.getLong(idxStartTime));
|
||||
stats.setStartTime(cursor.getLong(idxStartTime));
|
||||
}
|
||||
if (!cursor.isNull(idxStopTime)) {
|
||||
track.setStopTime(cursor.getLong(idxStopTime));
|
||||
stats.setStopTime(cursor.getLong(idxStopTime));
|
||||
}
|
||||
if (!cursor.isNull(idxStopId)) {
|
||||
track.setStopId(cursor.getInt(idxStopId));
|
||||
@@ -277,13 +279,13 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
track.setNumberOfPoints(cursor.getInt(idxNumPoints));
|
||||
}
|
||||
if (!cursor.isNull(idxTotalDistance)) {
|
||||
track.setTotalDistance(cursor.getFloat(idxTotalDistance));
|
||||
stats.setTotalDistance(cursor.getFloat(idxTotalDistance));
|
||||
}
|
||||
if (!cursor.isNull(idxTotalTime)) {
|
||||
track.setTotalTime(cursor.getLong(idxTotalTime));
|
||||
stats.setTotalTime(cursor.getLong(idxTotalTime));
|
||||
}
|
||||
if (!cursor.isNull(idxMovingTime)) {
|
||||
track.setMovingTime(cursor.getLong(idxMovingTime));
|
||||
stats.setMovingTime(cursor.getLong(idxMovingTime));
|
||||
}
|
||||
if (!cursor.isNull(idxMaxlat)
|
||||
&& !cursor.isNull(idxMinlat)
|
||||
@@ -293,31 +295,25 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
int bottom = cursor.getInt(idxMinlat);
|
||||
int right = cursor.getInt(idxMaxlon);
|
||||
int left = cursor.getInt(idxMinlon);
|
||||
track.setBounds(left, top, right, bottom);
|
||||
}
|
||||
if (!cursor.isNull(idxAverageSpeed)) {
|
||||
track.setAverageSpeed(cursor.getFloat(idxAverageSpeed));
|
||||
}
|
||||
if (!cursor.isNull(idxAverageMovingSpeed)) {
|
||||
track.setAverageMovingSpeed(cursor.getFloat(idxAverageMovingSpeed));
|
||||
stats.setBounds(left, top, right, bottom);
|
||||
}
|
||||
if (!cursor.isNull(idxMaxSpeed)) {
|
||||
track.setMaxSpeed(cursor.getFloat(idxMaxSpeed));
|
||||
stats.setMaxSpeed(cursor.getFloat(idxMaxSpeed));
|
||||
}
|
||||
if (!cursor.isNull(idxMinElevation)) {
|
||||
track.setMinElevation(cursor.getFloat(idxMinElevation));
|
||||
stats.setMinElevation(cursor.getFloat(idxMinElevation));
|
||||
}
|
||||
if (!cursor.isNull(idxMaxElevation)) {
|
||||
track.setMaxElevation(cursor.getFloat(idxMaxElevation));
|
||||
stats.setMaxElevation(cursor.getFloat(idxMaxElevation));
|
||||
}
|
||||
if (!cursor.isNull(idxElevationGain)) {
|
||||
track.setTotalElevationGain(cursor.getFloat(idxElevationGain));
|
||||
stats.setTotalElevationGain(cursor.getFloat(idxElevationGain));
|
||||
}
|
||||
if (!cursor.isNull(idxMinGrade)) {
|
||||
track.setMinGrade(cursor.getFloat(idxMinGrade));
|
||||
stats.setMinGrade(cursor.getFloat(idxMinGrade));
|
||||
}
|
||||
if (!cursor.isNull(idxMaxGrade)) {
|
||||
track.setMaxGrade(cursor.getFloat(idxMaxGrade));
|
||||
stats.setMaxGrade(cursor.getFloat(idxMaxGrade));
|
||||
}
|
||||
return track;
|
||||
}
|
||||
@@ -343,10 +339,6 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
int idxTotalTime = cursor.getColumnIndexOrThrow(WaypointsColumns.TOTALTIME);
|
||||
int idxMovingTime =
|
||||
cursor.getColumnIndexOrThrow(WaypointsColumns.MOVINGTIME);
|
||||
int idxAverageSpeed =
|
||||
cursor.getColumnIndexOrThrow(WaypointsColumns.AVGSPEED);
|
||||
int idxAverageMovingSpeed =
|
||||
cursor.getColumnIndexOrThrow(WaypointsColumns.AVGMOVINGSPEED);
|
||||
int idxMaxSpeed = cursor.getColumnIndexOrThrow(WaypointsColumns.MAXSPEED);
|
||||
int idxMinElevation =
|
||||
cursor.getColumnIndexOrThrow(WaypointsColumns.MINELEVATION);
|
||||
@@ -366,6 +358,8 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
int idxSpeed = cursor.getColumnIndexOrThrow(WaypointsColumns.SPEED);
|
||||
|
||||
Waypoint waypoint = new Waypoint();
|
||||
TripStatistics stats = waypoint.getStatistics();
|
||||
|
||||
if (!cursor.isNull(idxId)) {
|
||||
waypoint.setId(cursor.getLong(idxId));
|
||||
}
|
||||
@@ -394,7 +388,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
waypoint.setDuration(cursor.getLong(idxDuration));
|
||||
}
|
||||
if (!cursor.isNull(idxStartTime)) {
|
||||
waypoint.setStartTime(cursor.getLong(idxStartTime));
|
||||
stats.setStartTime(cursor.getLong(idxStartTime));
|
||||
}
|
||||
if (!cursor.isNull(idxStartId)) {
|
||||
waypoint.setStartId(cursor.getLong(idxStartId));
|
||||
@@ -403,37 +397,31 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
waypoint.setStopId(cursor.getLong(idxStopId));
|
||||
}
|
||||
if (!cursor.isNull(idxTotalDistance)) {
|
||||
waypoint.setTotalDistance(cursor.getFloat(idxTotalDistance));
|
||||
stats.setTotalDistance(cursor.getFloat(idxTotalDistance));
|
||||
}
|
||||
if (!cursor.isNull(idxTotalTime)) {
|
||||
waypoint.setTotalTime(cursor.getLong(idxTotalTime));
|
||||
stats.setTotalTime(cursor.getLong(idxTotalTime));
|
||||
}
|
||||
if (!cursor.isNull(idxMovingTime)) {
|
||||
waypoint.setMovingTime(cursor.getLong(idxMovingTime));
|
||||
}
|
||||
if (!cursor.isNull(idxAverageSpeed)) {
|
||||
waypoint.setAverageSpeed(cursor.getFloat(idxAverageSpeed));
|
||||
}
|
||||
if (!cursor.isNull(idxAverageMovingSpeed)) {
|
||||
waypoint.setAverageMovingSpeed(cursor.getFloat(idxAverageMovingSpeed));
|
||||
stats.setMovingTime(cursor.getLong(idxMovingTime));
|
||||
}
|
||||
if (!cursor.isNull(idxMaxSpeed)) {
|
||||
waypoint.setMaxSpeed(cursor.getFloat(idxMaxSpeed));
|
||||
stats.setMaxSpeed(cursor.getFloat(idxMaxSpeed));
|
||||
}
|
||||
if (!cursor.isNull(idxMinElevation)) {
|
||||
waypoint.setMinElevation(cursor.getFloat(idxMinElevation));
|
||||
stats.setMinElevation(cursor.getFloat(idxMinElevation));
|
||||
}
|
||||
if (!cursor.isNull(idxMaxElevation)) {
|
||||
waypoint.setMaxElevation(cursor.getFloat(idxMaxElevation));
|
||||
stats.setMaxElevation(cursor.getFloat(idxMaxElevation));
|
||||
}
|
||||
if (!cursor.isNull(idxElevationGain)) {
|
||||
waypoint.setTotalElevationGain(cursor.getFloat(idxElevationGain));
|
||||
stats.setTotalElevationGain(cursor.getFloat(idxElevationGain));
|
||||
}
|
||||
if (!cursor.isNull(idxMinGrade)) {
|
||||
waypoint.setMinGrade(cursor.getFloat(idxMinGrade));
|
||||
stats.setMinGrade(cursor.getFloat(idxMinGrade));
|
||||
}
|
||||
if (!cursor.isNull(idxMaxGrade)) {
|
||||
waypoint.setMaxGrade(cursor.getFloat(idxMaxGrade));
|
||||
stats.setMaxGrade(cursor.getFloat(idxMaxGrade));
|
||||
}
|
||||
|
||||
Location location = new Location("");
|
||||
@@ -494,7 +482,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
if (nextWaypoint != null) {
|
||||
Log.d(MyTracksProvider.TAG, "Correcting marker " + nextWaypoint.getId()
|
||||
+ " after deleted marker " + deletedWaypoint.getId());
|
||||
nextWaypoint.combine(deletedWaypoint);
|
||||
nextWaypoint.getStatistics().merge(deletedWaypoint.getStatistics());
|
||||
nextWaypoint.setDescription(
|
||||
descriptionGenerator.generateWaypointDescription(nextWaypoint));
|
||||
if (!updateWaypoint(nextWaypoint)) {
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
|
||||
import android.location.Location;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
@@ -24,7 +26,10 @@ import java.util.ArrayList;
|
||||
/**
|
||||
* A class representing a (GPS) Track.
|
||||
*
|
||||
* TODO: hashCode and equals
|
||||
*
|
||||
* @author Leif Hendrik Wilden
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class Track implements Parcelable {
|
||||
|
||||
@@ -34,6 +39,7 @@ public class Track implements Parcelable {
|
||||
public static class Creator implements Parcelable.Creator<Track> {
|
||||
|
||||
public Track createFromParcel(Parcel source) {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
Track track = new Track();
|
||||
track.id = source.readLong();
|
||||
track.name = source.readString();
|
||||
@@ -42,28 +48,14 @@ public class Track implements Parcelable {
|
||||
track.category = source.readString();
|
||||
track.startId = source.readLong();
|
||||
track.stopId = source.readLong();
|
||||
track.startTime = source.readLong();
|
||||
track.stopTime = source.readLong();
|
||||
track.totalDistance = source.readDouble();
|
||||
track.totalTime = source.readLong();
|
||||
track.movingTime = source.readLong();
|
||||
track.averageSpeed = source.readDouble();
|
||||
track.averageMovingSpeed = source.readDouble();
|
||||
track.maxSpeed = source.readDouble();
|
||||
track.minElevation = source.readDouble();
|
||||
track.maxElevation = source.readDouble();
|
||||
track.totalElevationGain = source.readDouble();
|
||||
track.minGrade = source.readDouble();
|
||||
track.maxGrade = source.readDouble();
|
||||
track.left = source.readInt();
|
||||
track.top = source.readInt();
|
||||
track.right = source.readInt();
|
||||
track.bottom = source.readInt();
|
||||
track.stats = source.readParcelable(classLoader);
|
||||
|
||||
track.numberOfPoints = source.readInt();
|
||||
for (int i = 0; i < track.numberOfPoints; ++i) {
|
||||
Location loc = source.readParcelable(null);
|
||||
Location loc = source.readParcelable(classLoader);
|
||||
track.locations.add(loc);
|
||||
}
|
||||
|
||||
return track;
|
||||
}
|
||||
|
||||
@@ -75,10 +67,16 @@ public class Track implements Parcelable {
|
||||
public static final Creator CREATOR = new Creator();
|
||||
|
||||
/**
|
||||
* The track points.
|
||||
* The track points (which may not have been loaded).
|
||||
*/
|
||||
private ArrayList<Location> locations = new ArrayList<Location>();
|
||||
|
||||
/**
|
||||
* The number of location points (present even if the points themselves were
|
||||
* not loaded).
|
||||
*/
|
||||
private int numberOfPoints = 0;
|
||||
|
||||
private long id = -1;
|
||||
private String name = "";
|
||||
private String description = "";
|
||||
@@ -87,34 +85,9 @@ public class Track implements Parcelable {
|
||||
private long stopId = -1;
|
||||
private String category = "";
|
||||
|
||||
// Fields derived from locations. Use setDerivedFields() to set them:
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
private long startTime = -1;
|
||||
private long stopTime = -1;
|
||||
private int numberOfPoints = 0;
|
||||
private double totalDistance = 0;
|
||||
private long totalTime = 0;
|
||||
private long movingTime = 0;
|
||||
private int left;
|
||||
private int top;
|
||||
private int right;
|
||||
private int bottom;
|
||||
|
||||
private double averageSpeed = 0;
|
||||
private double averageMovingSpeed = 0;
|
||||
private double maxSpeed = 0;
|
||||
private double minElevation = 0;
|
||||
private double maxElevation = 0;
|
||||
private double totalElevationGain = 0;
|
||||
private double minGrade = 0;
|
||||
private double maxGrade = 0;
|
||||
private TripStatistics stats = new TripStatistics();
|
||||
|
||||
public Track() {
|
||||
left = Integer.MAX_VALUE;
|
||||
top = Integer.MIN_VALUE;
|
||||
right = Integer.MIN_VALUE;
|
||||
bottom = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
@@ -125,23 +98,8 @@ public class Track implements Parcelable {
|
||||
dest.writeString(category);
|
||||
dest.writeLong(startId);
|
||||
dest.writeLong(stopId);
|
||||
dest.writeLong(startTime);
|
||||
dest.writeLong(stopTime);
|
||||
dest.writeDouble(totalDistance);
|
||||
dest.writeLong(totalTime);
|
||||
dest.writeLong(movingTime);
|
||||
dest.writeDouble(averageSpeed);
|
||||
dest.writeDouble(averageMovingSpeed);
|
||||
dest.writeDouble(maxSpeed);
|
||||
dest.writeDouble(minElevation);
|
||||
dest.writeDouble(maxElevation);
|
||||
dest.writeDouble(totalElevationGain);
|
||||
dest.writeDouble(minGrade);
|
||||
dest.writeDouble(maxGrade);
|
||||
dest.writeInt(left);
|
||||
dest.writeInt(top);
|
||||
dest.writeInt(right);
|
||||
dest.writeInt(bottom);
|
||||
dest.writeParcelable(stats, 0);
|
||||
|
||||
dest.writeInt(numberOfPoints);
|
||||
for (int i = 0; i < numberOfPoints; ++i) {
|
||||
dest.writeParcelable(locations.get(i), 0);
|
||||
@@ -151,29 +109,6 @@ public class Track implements Parcelable {
|
||||
// Getters and setters:
|
||||
//---------------------
|
||||
|
||||
public int getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public int getTop() {
|
||||
return top;
|
||||
}
|
||||
|
||||
public int getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
public int getBottom() {
|
||||
return bottom;
|
||||
}
|
||||
|
||||
public void setBounds(int aLeft, int aTop, int aRight, int aBottom) {
|
||||
left = aLeft;
|
||||
top = aTop;
|
||||
right = aRight;
|
||||
bottom = aBottom;
|
||||
}
|
||||
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
@@ -186,46 +121,6 @@ public class Track implements Parcelable {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public double getTotalDistance() {
|
||||
return totalDistance;
|
||||
}
|
||||
|
||||
public void setTotalDistance(double totalDistance) {
|
||||
this.totalDistance = totalDistance;
|
||||
}
|
||||
|
||||
public long getTotalTime() {
|
||||
return totalTime;
|
||||
}
|
||||
|
||||
public void setTotalTime(long totalTime) {
|
||||
this.totalTime = totalTime;
|
||||
}
|
||||
|
||||
public long getMovingTime() {
|
||||
return movingTime;
|
||||
}
|
||||
|
||||
public void setMovingTime(long movingTime) {
|
||||
this.movingTime = movingTime;
|
||||
}
|
||||
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(long startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public long getStopTime() {
|
||||
return stopTime;
|
||||
}
|
||||
|
||||
public void setStopTime(long stopTime) {
|
||||
this.stopTime = stopTime;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -274,70 +169,6 @@ public class Track implements Parcelable {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public double getAverageSpeed() {
|
||||
return averageSpeed;
|
||||
}
|
||||
|
||||
public void setAverageSpeed(double averageSpeed) {
|
||||
this.averageSpeed = averageSpeed;
|
||||
}
|
||||
|
||||
public double getAverageMovingSpeed() {
|
||||
return averageMovingSpeed;
|
||||
}
|
||||
|
||||
public void setAverageMovingSpeed(double averageMovingSpeed) {
|
||||
this.averageMovingSpeed = averageMovingSpeed;
|
||||
}
|
||||
|
||||
public double getMaxSpeed() {
|
||||
return maxSpeed;
|
||||
}
|
||||
|
||||
public void setMaxSpeed(double maxSpeed) {
|
||||
this.maxSpeed = maxSpeed;
|
||||
}
|
||||
|
||||
public double getMinElevation() {
|
||||
return minElevation;
|
||||
}
|
||||
|
||||
public void setMinElevation(double minElevation) {
|
||||
this.minElevation = minElevation;
|
||||
}
|
||||
|
||||
public double getMaxElevation() {
|
||||
return maxElevation;
|
||||
}
|
||||
|
||||
public void setMaxElevation(double maxElevation) {
|
||||
this.maxElevation = maxElevation;
|
||||
}
|
||||
|
||||
public double getTotalElevationGain() {
|
||||
return totalElevationGain;
|
||||
}
|
||||
|
||||
public void setTotalElevationGain(double totalElevationGain) {
|
||||
this.totalElevationGain = totalElevationGain;
|
||||
}
|
||||
|
||||
public double getMinGrade() {
|
||||
return minGrade;
|
||||
}
|
||||
|
||||
public void setMinGrade(double minGrade) {
|
||||
this.minGrade = minGrade;
|
||||
}
|
||||
|
||||
public double getMaxGrade() {
|
||||
return maxGrade;
|
||||
}
|
||||
|
||||
public void setMaxGrade(double maxGrade) {
|
||||
this.maxGrade = maxGrade;
|
||||
}
|
||||
|
||||
public int getNumberOfPoints() {
|
||||
return numberOfPoints;
|
||||
}
|
||||
@@ -357,4 +188,12 @@ public class Track implements Parcelable {
|
||||
public void setLocations(ArrayList<Location> locations) {
|
||||
this.locations = locations;
|
||||
}
|
||||
|
||||
public TripStatistics getStatistics() {
|
||||
return stats;
|
||||
}
|
||||
|
||||
public void setStatistics(TripStatistics stats) {
|
||||
this.stats = stats;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
|
||||
import android.location.Location;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
@@ -23,16 +25,20 @@ import android.os.Parcelable;
|
||||
* A way point. It has a location, meta data such as name, description,
|
||||
* category, and icon, plus it can store track statistics for a "sub-track".
|
||||
*
|
||||
* TODO: hashCode and equals
|
||||
*
|
||||
* @author Leif Hendrik Wilden
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public final class Waypoint implements Parcelable {
|
||||
|
||||
/**
|
||||
* Creator for a Waypoint object
|
||||
* Creator for a Waypoint object
|
||||
*/
|
||||
public static class Creator implements Parcelable.Creator<Waypoint> {
|
||||
|
||||
public Waypoint createFromParcel(Parcel source) {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
Waypoint waypoint = new Waypoint();
|
||||
waypoint.id = source.readLong();
|
||||
waypoint.name = source.readString();
|
||||
@@ -41,26 +47,13 @@ public final class Waypoint implements Parcelable {
|
||||
waypoint.icon = source.readString();
|
||||
waypoint.trackId = source.readLong();
|
||||
waypoint.type = source.readInt();
|
||||
waypoint.length = source.readDouble();
|
||||
waypoint.duration = source.readLong();
|
||||
waypoint.startTime = source.readLong();
|
||||
waypoint.startId = source.readLong();
|
||||
waypoint.stopId = source.readLong();
|
||||
waypoint.stats = source.readParcelable(classLoader);
|
||||
byte hasLocation = source.readByte();
|
||||
if (hasLocation > 0) {
|
||||
waypoint.location = source.readParcelable(null);
|
||||
waypoint.location = source.readParcelable(classLoader);
|
||||
}
|
||||
waypoint.totalDistance = source.readDouble();
|
||||
waypoint.totalTime = source.readLong();
|
||||
waypoint.movingTime = source.readLong();
|
||||
waypoint.averageSpeed = source.readDouble();
|
||||
waypoint.averageMovingSpeed = source.readDouble();
|
||||
waypoint.maxSpeed = source.readDouble();
|
||||
waypoint.minElevation = source.readDouble();
|
||||
waypoint.maxElevation = source.readDouble();
|
||||
waypoint.totalElevationGain = source.readDouble();
|
||||
waypoint.minGrade = source.readDouble();
|
||||
waypoint.maxGrade = source.readDouble();
|
||||
return waypoint;
|
||||
}
|
||||
|
||||
@@ -84,28 +77,18 @@ public final class Waypoint implements Parcelable {
|
||||
|
||||
private Location location;
|
||||
|
||||
/** Length along the track in meters. */
|
||||
private double length = 0;
|
||||
/** Time along the track in seconds. */
|
||||
private long duration = 0;
|
||||
/** Start time of a segment */
|
||||
private long startTime = -1;
|
||||
/** Start track point id */
|
||||
private long startId = -1;
|
||||
/** Stop track point id */
|
||||
private long stopId = -1;
|
||||
|
||||
private double totalDistance = 0;
|
||||
private long totalTime = 0;
|
||||
private long movingTime = 0;
|
||||
private double averageSpeed = 0;
|
||||
private double averageMovingSpeed = 0;
|
||||
private double maxSpeed = 0;
|
||||
private double minElevation = 0;
|
||||
private double maxElevation = 0;
|
||||
private double totalElevationGain = 0;
|
||||
private double minGrade = 0;
|
||||
private double maxGrade = 0;
|
||||
private TripStatistics stats = new TripStatistics();
|
||||
|
||||
/** The length of the track, without smoothing. */
|
||||
private double length;
|
||||
|
||||
/** The total duration of the track (not from the last waypoint) */
|
||||
private long duration;
|
||||
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(id);
|
||||
@@ -115,46 +98,13 @@ public final class Waypoint implements Parcelable {
|
||||
dest.writeString(icon);
|
||||
dest.writeLong(trackId);
|
||||
dest.writeInt(type);
|
||||
dest.writeDouble(length);
|
||||
dest.writeLong(duration);
|
||||
dest.writeLong(startTime);
|
||||
dest.writeLong(startId);
|
||||
dest.writeLong(stopId);
|
||||
dest.writeParcelable(stats, 0);
|
||||
dest.writeByte(location == null ? (byte) 0 : (byte) 1);
|
||||
if (location != null) {
|
||||
dest.writeParcelable(location, 0);
|
||||
}
|
||||
dest.writeDouble(totalDistance);
|
||||
dest.writeLong(totalTime);
|
||||
dest.writeLong(movingTime);
|
||||
dest.writeDouble(averageSpeed);
|
||||
dest.writeDouble(averageMovingSpeed);
|
||||
dest.writeDouble(maxSpeed);
|
||||
dest.writeDouble(minElevation);
|
||||
dest.writeDouble(maxElevation);
|
||||
dest.writeDouble(totalElevationGain);
|
||||
dest.writeDouble(minGrade);
|
||||
dest.writeDouble(maxGrade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines the statistics from another (earlier) waypoint with this one.
|
||||
* This is needed when the user deletes a statistic waypoint.
|
||||
*
|
||||
* @param other the other waypoint
|
||||
*/
|
||||
public void combine(Waypoint other) {
|
||||
totalTime += other.totalTime;
|
||||
movingTime += other.movingTime;
|
||||
totalDistance += other.totalDistance;
|
||||
totalElevationGain += other.totalElevationGain;
|
||||
averageSpeed = totalDistance / totalTime;
|
||||
averageMovingSpeed = totalDistance / movingTime;
|
||||
maxSpeed = Math.max(maxSpeed, other.maxSpeed);
|
||||
minElevation = Math.min(minElevation, other.minElevation);
|
||||
maxElevation = Math.max(maxElevation, other.maxElevation);
|
||||
minGrade = Math.min(minGrade, other.minGrade);
|
||||
maxGrade = Math.max(maxGrade, other.maxGrade);
|
||||
}
|
||||
|
||||
// Getters and setters:
|
||||
@@ -188,30 +138,6 @@ public final class Waypoint implements Parcelable {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public double getTotalDistance() {
|
||||
return totalDistance;
|
||||
}
|
||||
|
||||
public void setTotalDistance(double totalDistance) {
|
||||
this.totalDistance = totalDistance;
|
||||
}
|
||||
|
||||
public long getTotalTime() {
|
||||
return totalTime;
|
||||
}
|
||||
|
||||
public void setTotalTime(long totalTime) {
|
||||
this.totalTime = totalTime;
|
||||
}
|
||||
|
||||
public long getMovingTime() {
|
||||
return movingTime;
|
||||
}
|
||||
|
||||
public void setMovingTime(long movingTime) {
|
||||
this.movingTime = movingTime;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -232,30 +158,6 @@ public final class Waypoint implements Parcelable {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public double getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(double length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(long duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(long startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public long getStartId() {
|
||||
return startId;
|
||||
}
|
||||
@@ -288,71 +190,34 @@ public final class Waypoint implements Parcelable {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public double getAverageSpeed() {
|
||||
return averageSpeed;
|
||||
}
|
||||
|
||||
public void setAverageSpeed(double averageSpeed) {
|
||||
this.averageSpeed = averageSpeed;
|
||||
}
|
||||
|
||||
public double getAverageMovingSpeed() {
|
||||
return averageMovingSpeed;
|
||||
}
|
||||
|
||||
public void setAverageMovingSpeed(double averageMovingSpeed) {
|
||||
this.averageMovingSpeed = averageMovingSpeed;
|
||||
}
|
||||
|
||||
public double getMaxSpeed() {
|
||||
return maxSpeed;
|
||||
}
|
||||
|
||||
public void setMaxSpeed(double maxSpeed) {
|
||||
this.maxSpeed = maxSpeed;
|
||||
}
|
||||
|
||||
public double getMinElevation() {
|
||||
return minElevation;
|
||||
}
|
||||
|
||||
public void setMinElevation(double minElevation) {
|
||||
this.minElevation = minElevation;
|
||||
}
|
||||
|
||||
public double getMaxElevation() {
|
||||
return maxElevation;
|
||||
}
|
||||
|
||||
public void setMaxElevation(double maxElevation) {
|
||||
this.maxElevation = maxElevation;
|
||||
}
|
||||
|
||||
public double getTotalElevationGain() {
|
||||
return totalElevationGain;
|
||||
}
|
||||
|
||||
public void setTotalElevationGain(double totalElevationGain) {
|
||||
this.totalElevationGain = totalElevationGain;
|
||||
}
|
||||
|
||||
public double getMinGrade() {
|
||||
return minGrade;
|
||||
}
|
||||
|
||||
public void setMinGrade(double minGrade) {
|
||||
this.minGrade = minGrade;
|
||||
}
|
||||
|
||||
public double getMaxGrade() {
|
||||
return maxGrade;
|
||||
}
|
||||
|
||||
public void setMaxGrade(double maxGrade) {
|
||||
this.maxGrade = maxGrade;
|
||||
}
|
||||
|
||||
public void setLocation(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public TripStatistics getStatistics() {
|
||||
return stats;
|
||||
}
|
||||
|
||||
public void setStatistics(TripStatistics stats) {
|
||||
this.stats = stats;
|
||||
}
|
||||
|
||||
// WARNING: These fields are used for internal state keeping. You probably
|
||||
// want to look at getStatistics instead.
|
||||
|
||||
public double getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(double length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(long duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -16,7 +16,7 @@
|
||||
package com.google.android.apps.mytracks.io;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||
import com.google.android.apps.mytracks.util.MyTracksUtils;
|
||||
|
||||
import android.location.Location;
|
||||
@@ -214,21 +214,21 @@ public class GpxImport {
|
||||
|
||||
if (locations.size() > 0) {
|
||||
long startTime = locations.get(0).getTime();
|
||||
track.setStartTime(startTime);
|
||||
|
||||
// Calculate statistics for the imported track
|
||||
TripStatistics stats = new TripStatistics(startTime);
|
||||
TripStatisticsBuilder statsBuilder = new TripStatisticsBuilder();
|
||||
statsBuilder.resumeAt(startTime);
|
||||
for (Location location : locations) {
|
||||
if (MyTracksUtils.isValidLocation(location)) {
|
||||
/* Any time works here. The totalTime will be set by "pauseAt" later: */
|
||||
stats.addLocation(location, location.getTime());
|
||||
statsBuilder.addLocation(location, location.getTime());
|
||||
}
|
||||
}
|
||||
long lastPointTime = locations.get(locations.size() - 1).getTime();
|
||||
stats.pauseAt(lastPointTime);
|
||||
track.setStopTime(lastPointTime);
|
||||
|
||||
stats.fillStatisticsForTrack(track);
|
||||
long lastPointTime = locations.get(locations.size() - 1).getTime();
|
||||
statsBuilder.pauseAt(lastPointTime);
|
||||
|
||||
track.setStatistics(statsBuilder.getStatistics());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
|
||||
import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
|
||||
import com.google.android.apps.mytracks.io.gdata.GDataWrapper.QueryFunction;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.ResourceUtils;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
@@ -429,6 +430,7 @@ public class SendToDocs {
|
||||
String worksheetId) throws IOException {
|
||||
String worksheetUri = String.format(DOCS_SPREADSHEET_URL_FORMAT,
|
||||
spreadsheetId, worksheetId);
|
||||
TripStatistics stats = track.getStatistics();
|
||||
|
||||
/* Prepare the Post-Text we are going to send. */
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -437,29 +439,29 @@ public class SendToDocs {
|
||||
+ "2006/extended'>");
|
||||
appendTag("name", track.getName(), sb);
|
||||
appendTag("description", track.getDescription(), sb);
|
||||
appendTag("date", String.format("%tc", track.getStartTime()), sb);
|
||||
appendTag("date", String.format("%tc", stats.getStartTime()), sb);
|
||||
appendTag("totaltime", StringUtils.formatTimeAlwaysShowingHours(
|
||||
track.getTotalTime()), sb);
|
||||
stats.getTotalTime()), sb);
|
||||
appendTag("movingtime", StringUtils.formatTimeAlwaysShowingHours(
|
||||
track.getMovingTime()), sb);
|
||||
appendLargeUnitsTag("distance", track.getTotalDistance() / 1000, sb);
|
||||
stats.getMovingTime()), sb);
|
||||
appendLargeUnitsTag("distance", stats.getTotalDistance() / 1000, sb);
|
||||
appendTag("distanceunit",
|
||||
metricUnits
|
||||
? activity.getString(R.string.kilometer)
|
||||
: activity.getString(R.string.mile),
|
||||
sb);
|
||||
appendLargeUnitsTag("averagespeed", track.getAverageSpeed() * 3.6, sb);
|
||||
appendLargeUnitsTag("averagespeed", stats.getAverageSpeed() * 3.6, sb);
|
||||
appendLargeUnitsTag("averagemovingspeed",
|
||||
track.getAverageMovingSpeed() * 3.6, sb);
|
||||
appendLargeUnitsTag("maxspeed", track.getMaxSpeed() * 3.6, sb);
|
||||
stats.getAverageMovingSpeed() * 3.6, sb);
|
||||
appendLargeUnitsTag("maxspeed", stats.getMaxSpeed() * 3.6, sb);
|
||||
appendTag("speedunit",
|
||||
metricUnits
|
||||
? activity.getString(R.string.kilometer_per_hour)
|
||||
: activity.getString(R.string.mile_per_hour),
|
||||
sb);
|
||||
appendSmallUnitsTag("elevationgain", track.getTotalElevationGain(), sb);
|
||||
appendSmallUnitsTag("minelevation", track.getMinElevation(), sb);
|
||||
appendSmallUnitsTag("maxelevation", track.getMaxElevation(), sb);
|
||||
appendSmallUnitsTag("elevationgain", stats.getTotalElevationGain(), sb);
|
||||
appendSmallUnitsTag("minelevation", stats.getMinElevation(), sb);
|
||||
appendSmallUnitsTag("maxelevation", stats.getMaxElevation(), sb);
|
||||
appendTag("elevationunit",
|
||||
metricUnits
|
||||
? activity.getString(R.string.meter)
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TrackBuffer;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.MyTracksUtils;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
@@ -105,12 +106,14 @@ public class SendToMyMaps {
|
||||
|
||||
// Create segments from each full track:
|
||||
Track segment = new Track();
|
||||
TripStatistics segmentStats = segment.getStatistics();
|
||||
TripStatistics trackStats = track.getStatistics();
|
||||
segment.setId(track.getId());
|
||||
segment.setName(track.getName());
|
||||
segment.setDescription(/* track.getDescription() */ "");
|
||||
segment.setCategory(track.getCategory());
|
||||
segment.setStartTime(track.getStartTime());
|
||||
segment.setStopTime(track.getStopTime());
|
||||
segmentStats.setStartTime(trackStats.getStartTime());
|
||||
segmentStats.setStopTime(trackStats.getStopTime());
|
||||
boolean startNewTrackSegment = false;
|
||||
for (int i = 0; i < buffer.getLocationsLoaded(); ++i) {
|
||||
Location loc = buffer.get(i);
|
||||
@@ -134,8 +137,8 @@ public class SendToMyMaps {
|
||||
|
||||
if (loc.getLatitude() <= 90) {
|
||||
segment.addLocation(loc);
|
||||
if (segment.getStartTime() < 0) {
|
||||
segment.setStartTime(loc.getTime());
|
||||
if (segmentStats.getStartTime() < 0) {
|
||||
segmentStats.setStartTime(loc.getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,8 +162,10 @@ public class SendToMyMaps {
|
||||
*/
|
||||
private void prepareTrackSegment(
|
||||
Track segment, ArrayList<Track> splitTracks) {
|
||||
if (segment.getStopTime() < 0 && segment.getLocations().size() > 0) {
|
||||
segment.setStopTime(segment.getLocations().size() - 1);
|
||||
TripStatistics segmentStats = segment.getStatistics();
|
||||
if (segmentStats.getStopTime() < 0
|
||||
&& segment.getLocations().size() > 0) {
|
||||
segmentStats.setStopTime(segment.getLocations().size() - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.google.android.apps.mytracks.services;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.TripStatisticsData;
|
||||
|
||||
/**
|
||||
* MyTracks service.
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||
import com.google.android.apps.mytracks.util.MyTracksUtils;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -92,8 +93,8 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
*/
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
|
||||
private TripStatistics stats = new TripStatistics();
|
||||
private TripStatistics waypointStats = new TripStatistics();
|
||||
private TripStatisticsBuilder statsBuilder = new TripStatisticsBuilder();
|
||||
private TripStatisticsBuilder waypointStatsBuilder = new TripStatisticsBuilder();
|
||||
|
||||
/**
|
||||
* Current length of the recorded track. This length is calculated from the
|
||||
@@ -229,6 +230,7 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
if (lastRecordedLocation != null
|
||||
&& lastRecordedLocation.getLatitude() < 90) {
|
||||
ContentValues values = new ContentValues();
|
||||
TripStatistics stats = statsBuilder.getStatistics();
|
||||
if (recordingTrack.getStartId() < 0) {
|
||||
values.put(TracksColumns.STARTID, pointId);
|
||||
recordingTrack.setStartId(pointId);
|
||||
@@ -271,10 +273,11 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
private void updateCurrentWaypoint() {
|
||||
if (currentWaypointId >= 0) {
|
||||
ContentValues values = new ContentValues();
|
||||
TripStatistics waypointStats = waypointStatsBuilder.getStatistics();
|
||||
values.put(WaypointsColumns.STARTTIME, waypointStats.getStartTime());
|
||||
values.put(WaypointsColumns.LENGTH, length);
|
||||
values.put(WaypointsColumns.DURATION,
|
||||
System.currentTimeMillis() - stats.getStartTime());
|
||||
values.put(WaypointsColumns.DURATION, System.currentTimeMillis()
|
||||
- statsBuilder.getStatistics().getStartTime());
|
||||
values.put(WaypointsColumns.TOTALDISTANCE,
|
||||
waypointStats.getTotalDistance());
|
||||
values.put(WaypointsColumns.TOTALTIME, waypointStats.getTotalTime());
|
||||
@@ -397,7 +400,9 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
return;
|
||||
}
|
||||
|
||||
stats = new TripStatistics(track.getStartTime());
|
||||
TripStatistics stats = track.getStatistics();
|
||||
statsBuilder = new TripStatisticsBuilder();
|
||||
statsBuilder.resumeAt(stats.getStartTime());
|
||||
if (executer != null) {
|
||||
executer.scheduleTask(announcementFrequency * 60000);
|
||||
}
|
||||
@@ -410,10 +415,11 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
Waypoint waypoint = providerUtils.getFirstWaypoint(recordingTrackId);
|
||||
if (waypoint != null) {
|
||||
currentWaypointId = waypoint.getId();
|
||||
waypointStats = new TripStatistics(waypoint);
|
||||
waypointStatsBuilder = new TripStatisticsBuilder(waypoint.getStatistics());
|
||||
} else {
|
||||
// This should never happen, but we got to do something so life goes on:
|
||||
waypointStats = new TripStatistics(track.getStartTime());
|
||||
waypointStatsBuilder = new TripStatisticsBuilder();
|
||||
waypointStatsBuilder.resumeAt(stats.getStartTime());
|
||||
currentWaypointId = -1;
|
||||
}
|
||||
|
||||
@@ -427,7 +433,7 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
do {
|
||||
Location location = providerUtils.createLocation(cursor);
|
||||
if (MyTracksUtils.isValidLocation(location)) {
|
||||
stats.addLocation(location, location.getTime());
|
||||
statsBuilder.addLocation(location, location.getTime());
|
||||
if (lastValidLocation != null) {
|
||||
length += location.distanceTo(lastValidLocation);
|
||||
}
|
||||
@@ -435,9 +441,9 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
}
|
||||
} while (cursor.moveToPrevious());
|
||||
}
|
||||
stats.setMovingTime(track.getMovingTime());
|
||||
stats.pauseAt(track.getStopTime());
|
||||
stats.resume();
|
||||
statsBuilder.getStatistics().setMovingTime(stats.getMovingTime());
|
||||
statsBuilder.pauseAt(stats.getStopTime());
|
||||
statsBuilder.resume();
|
||||
} else {
|
||||
Log.e(MyTracksConstants.TAG, "Could not get track points cursor.");
|
||||
}
|
||||
@@ -494,12 +500,12 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
|
||||
if (MyTracksUtils.isValidLocation(location)) {
|
||||
long now = System.currentTimeMillis();
|
||||
stats.addLocation(location, now);
|
||||
waypointStats.addLocation(location, now);
|
||||
statsBuilder.addLocation(location, now);
|
||||
waypointStatsBuilder.addLocation(location, now);
|
||||
}
|
||||
|
||||
// Update the idle time if needed.
|
||||
locationListenerPolicy.updateIdleTime(stats.getIdleTime());
|
||||
locationListenerPolicy.updateIdleTime(statsBuilder.getIdleTime());
|
||||
if (currentRecordingInterval
|
||||
!= locationListenerPolicy.getDesiredPollingInterval()) {
|
||||
registerLocationListener();
|
||||
@@ -798,8 +804,8 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
public long insertWaypointMarker(Waypoint waypoint) {
|
||||
if (waypoint.getLocation() != null) {
|
||||
waypoint.setLength(length);
|
||||
waypoint.setDuration(
|
||||
waypoint.getLocation().getTime() - stats.getStartTime());
|
||||
waypoint.setDuration(waypoint.getLocation().getTime()
|
||||
- statsBuilder.getStatistics().getStartTime());
|
||||
Uri uri = providerUtils.insertWaypoint(waypoint);
|
||||
return Long.parseLong(uri.getLastPathSegment());
|
||||
}
|
||||
@@ -814,22 +820,35 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
* @return the unique id of the inserted marker
|
||||
*/
|
||||
public long insertStatisticsMarker(Location location) {
|
||||
StringUtils utils = new StringUtils(TrackRecordingService.this);
|
||||
|
||||
// Create a new waypoint to save
|
||||
Waypoint waypoint = new Waypoint();
|
||||
|
||||
// Set stop and total time in the stats data
|
||||
final long time = System.currentTimeMillis();
|
||||
waypointStatsBuilder.pauseAt(time);
|
||||
|
||||
// Override the duration - it's not the duration from the last waypoint, but
|
||||
// the duration from the beginning of the whole track
|
||||
waypoint.setDuration(time - statsBuilder.getStatistics().getStartTime());
|
||||
|
||||
// Set the rest of the waypoint data
|
||||
waypoint.setTrackId(recordingTrackId);
|
||||
waypoint.setType(Waypoint.TYPE_STATISTICS);
|
||||
waypoint.setName(TrackRecordingService.this.getString(R.string.statistics));
|
||||
waypointStats.fillStatisticsForWaypoint(waypoint);
|
||||
StringUtils utils = new StringUtils(TrackRecordingService.this);
|
||||
waypoint.setStatistics(waypointStatsBuilder.getStatistics());
|
||||
waypoint.setDescription(utils.generateWaypointDescription(waypoint));
|
||||
waypoint.setLocation(location);
|
||||
waypoint.setIcon(STATISTICS_ICON_URL);
|
||||
waypoint.setLength(length);
|
||||
final long time = System.currentTimeMillis();
|
||||
waypoint.setDuration(time - stats.getStartTime());
|
||||
waypoint.setStartTime(waypointStats.getStartTime());
|
||||
|
||||
waypoint.setStartId(providerUtils.getLastLocationId(recordingTrackId));
|
||||
Uri uri = providerUtils.insertWaypoint(waypoint);
|
||||
waypointStats = new TripStatistics(time);
|
||||
|
||||
// Create a new stats keeper for the next marker
|
||||
waypointStatsBuilder = new TripStatisticsBuilder();
|
||||
waypointStatsBuilder.resumeAt(time);
|
||||
updateCurrentWaypoint();
|
||||
return Long.parseLong(uri.getLastPathSegment());
|
||||
}
|
||||
@@ -858,8 +877,10 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
public long startNewTrack() {
|
||||
Log.d(MyTracksConstants.TAG, "TrackRecordingService.startNewTrack");
|
||||
Track track = new Track();
|
||||
TripStatistics trackStats = track.getStatistics();
|
||||
track.setName("new");
|
||||
track.setStartTime(System.currentTimeMillis());
|
||||
long startTime = System.currentTimeMillis();
|
||||
trackStats.setStartTime(startTime);
|
||||
track.setStartId(-1);
|
||||
Uri trackUri = providerUtils.insertTrack(track);
|
||||
long trackId = Long.parseLong(trackUri.getLastPathSegment());
|
||||
@@ -870,7 +891,8 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
currentWaypointId = insertStatisticsMarker(null);
|
||||
isRecording = true;
|
||||
isMoving = true;
|
||||
stats = new TripStatistics(track.getStartTime());
|
||||
statsBuilder = new TripStatisticsBuilder();
|
||||
statsBuilder.resumeAt(startTime);
|
||||
if (announcementFrequency != -1 && executer != null) {
|
||||
executer.scheduleTask(announcementFrequency * 60000);
|
||||
}
|
||||
@@ -912,9 +934,9 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
isRecording = false;
|
||||
Track recordingTrack = providerUtils.getTrack(recordingTrackId);
|
||||
if (recordingTrack != null) {
|
||||
recordingTrack.setStopTime(System.currentTimeMillis());
|
||||
recordingTrack.setTotalTime(
|
||||
recordingTrack.getStopTime() - recordingTrack.getStartTime());
|
||||
TripStatistics stats = recordingTrack.getStatistics();
|
||||
stats.setStopTime(System.currentTimeMillis());
|
||||
stats.setTotalTime(stats.getStopTime() - stats.getStartTime());
|
||||
long lastRecordedLocationId =
|
||||
providerUtils.getLastLocationId(recordingTrackId);
|
||||
ContentValues values = new ContentValues();
|
||||
@@ -922,8 +944,8 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
&& recordingTrack.getStopId() >= 0) {
|
||||
values.put(TracksColumns.STOPID, lastRecordedLocationId);
|
||||
}
|
||||
values.put(TracksColumns.STOPTIME, recordingTrack.getStopTime());
|
||||
values.put(TracksColumns.TOTALTIME, recordingTrack.getTotalTime());
|
||||
values.put(TracksColumns.STOPTIME, stats.getStopTime());
|
||||
values.put(TracksColumns.TOTALTIME, stats.getTotalTime());
|
||||
getContentResolver().update(TracksColumns.CONTENT_URI, values,
|
||||
"_id=" + recordingTrack.getId(), null);
|
||||
}
|
||||
@@ -951,7 +973,7 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
};
|
||||
|
||||
TripStatistics getTripStatistics() {
|
||||
return stats;
|
||||
return statsBuilder.getStatistics();
|
||||
}
|
||||
|
||||
Location getLastLocation() {
|
||||
|
||||
Executable → Regular
@@ -84,10 +84,23 @@ public class ExtremityMonitor {
|
||||
|
||||
/**
|
||||
* Sets the minimum and maximum values.
|
||||
* Useful when restoring state.
|
||||
*/
|
||||
public void set(double min, double max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum value.
|
||||
*/
|
||||
public void setMin(double min) {
|
||||
this.min = min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum value.
|
||||
*/
|
||||
public void setMax(double max) {
|
||||
this.max = max;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
package com.google.android.apps.mytracks.stats;
|
||||
parcelable TripStatisticsData;
|
||||
parcelable TripStatistics;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Copyright 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.stats;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
|
||||
import android.location.Location;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Statistics keeper for a trip.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class TripStatisticsBuilder {
|
||||
/**
|
||||
* Statistical data about the trip, which can be displayed to the user.
|
||||
*/
|
||||
private final TripStatistics data;
|
||||
|
||||
/**
|
||||
* The last location that the gps reported.
|
||||
*/
|
||||
private Location lastLocation = null;
|
||||
|
||||
/**
|
||||
* The last location that contributed to the stats. It is also the last
|
||||
* location the user was found to be moving.
|
||||
*/
|
||||
private Location lastMovingLocation = null;
|
||||
|
||||
/**
|
||||
* The current speed in meters/second as reported by the gps.
|
||||
*/
|
||||
private double currentSpeed;
|
||||
|
||||
/**
|
||||
* The current grade. This value is very noisy and not reported to the user.
|
||||
*/
|
||||
private double currentGrade;
|
||||
|
||||
/**
|
||||
* Is the trip currently paused?
|
||||
* All trips start paused.
|
||||
*/
|
||||
private boolean paused = true;
|
||||
|
||||
/**
|
||||
* A buffer of the last speed readings in meters/second.
|
||||
*/
|
||||
private final DoubleBuffer speedBuffer =
|
||||
new DoubleBuffer(MyTracksConstants.SPEED_SMOOTHING_FACTOR);
|
||||
|
||||
/**
|
||||
* A buffer of the recent elevation readings in meters.
|
||||
*/
|
||||
private final DoubleBuffer elevationBuffer =
|
||||
new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
|
||||
|
||||
/**
|
||||
* A buffer of the distance between recent gps readings in meters.
|
||||
*/
|
||||
private final DoubleBuffer distanceBuffer =
|
||||
new DoubleBuffer(MyTracksConstants.DISTANCE_SMOOTHING_FACTOR);
|
||||
|
||||
/**
|
||||
* A buffer of the recent grade calculations.
|
||||
*/
|
||||
private final DoubleBuffer gradeBuffer =
|
||||
new DoubleBuffer(MyTracksConstants.GRADE_SMOOTHING_FACTOR);
|
||||
|
||||
/**
|
||||
* The total number of locations in this trip.
|
||||
*/
|
||||
private long totalLocations = 0;
|
||||
|
||||
/**
|
||||
* Creates a new trip starting at the current system time.
|
||||
*/
|
||||
public TripStatisticsBuilder() {
|
||||
data = new TripStatistics();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new trip, starting with existing statistics data.
|
||||
*
|
||||
* @param statsData the statistics data to copy and start from
|
||||
*/
|
||||
public TripStatisticsBuilder(TripStatistics statsData) {
|
||||
data = new TripStatistics(statsData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a location to the current trip. This will update all of the internal
|
||||
* variables with this new location.
|
||||
*
|
||||
* @param currentLocation the current gps location
|
||||
* @param systemTime the time used for calculation of totalTime. This should
|
||||
* be the phone's time (not GPS time)
|
||||
* @return true if the person is moving
|
||||
*/
|
||||
public boolean addLocation(Location currentLocation, long systemTime) {
|
||||
if (paused) {
|
||||
Log.w(MyTracksConstants.TAG,
|
||||
"Tried to account for location while track is paused");
|
||||
return false;
|
||||
}
|
||||
|
||||
totalLocations++;
|
||||
|
||||
double elevationDifference = updateElevation(currentLocation.getAltitude());
|
||||
|
||||
// Update the "instant" values:
|
||||
data.setTotalTime(systemTime - data.getStartTime());
|
||||
currentSpeed = currentLocation.getSpeed();
|
||||
|
||||
// This was the 1st location added, remember it and do nothing else:
|
||||
if (lastLocation == null) {
|
||||
lastLocation = currentLocation;
|
||||
lastMovingLocation = currentLocation;
|
||||
return false;
|
||||
}
|
||||
|
||||
updateBounds(currentLocation);
|
||||
|
||||
// Don't do anything if we didn't move since last fix:
|
||||
double distance = lastLocation.distanceTo(currentLocation);
|
||||
if (distance < MyTracksConstants.MAX_NO_MOVEMENT_DISTANCE
|
||||
&& currentSpeed < MyTracksConstants.MAX_NO_MOVEMENT_SPEED) {
|
||||
lastLocation = currentLocation;
|
||||
return false;
|
||||
}
|
||||
|
||||
data.addTotalDistance(lastMovingLocation.distanceTo(currentLocation));
|
||||
updateSpeed(currentLocation.getTime(), currentSpeed,
|
||||
lastLocation.getTime(), lastLocation.getSpeed());
|
||||
|
||||
updateGrade(distance, elevationDifference);
|
||||
lastLocation = currentLocation;
|
||||
lastMovingLocation = currentLocation;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the track's bounding box to include the given location.
|
||||
*/
|
||||
private void updateBounds(Location location) {
|
||||
data.updateLatitudeExtremities(location.getLatitude());
|
||||
data.updateLongitudeExtremities(location.getLongitude());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the elevation measurements.
|
||||
*
|
||||
* @param elevation the current elevation
|
||||
*/
|
||||
// @VisibleForTesting
|
||||
double updateElevation(double elevation) {
|
||||
double oldSmoothedElevation = getSmoothedElevation();
|
||||
elevationBuffer.setNext(elevation);
|
||||
double smoothedElevation = getSmoothedElevation();
|
||||
data.updateElevationExtremities(smoothedElevation);
|
||||
double elevationDifference = elevationBuffer.isFull()
|
||||
? smoothedElevation - oldSmoothedElevation
|
||||
: 0.0;
|
||||
if (elevationDifference > 0) {
|
||||
data.addTotalElevationGain(elevationDifference);
|
||||
}
|
||||
return elevationDifference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the speed measurements.
|
||||
*
|
||||
* @param updateTime the time of the speed update
|
||||
* @param speed the current speed
|
||||
* @param lastLocationTime the time of the last speed update
|
||||
* @param lastLocationSpeed the speed of the last update
|
||||
*/
|
||||
// @VisibleForTesting
|
||||
void updateSpeed(long updateTime, double speed, long lastLocationTime,
|
||||
double lastLocationSpeed) {
|
||||
// We are now sure the user is moving.
|
||||
long timeDifference = updateTime - lastLocationTime;
|
||||
if (timeDifference < 0) {
|
||||
Log.e(MyTracksConstants.TAG,
|
||||
"Found negative time change: " + timeDifference);
|
||||
}
|
||||
data.addMovingTime(timeDifference);
|
||||
|
||||
if (isValidSpeed(updateTime, speed, lastLocationTime, lastLocationSpeed,
|
||||
speedBuffer)) {
|
||||
speedBuffer.setNext(speed);
|
||||
if (speed > data.getMaxSpeed()) {
|
||||
data.setMaxSpeed(speed);
|
||||
}
|
||||
double movingSpeed = data.getAverageMovingSpeed();
|
||||
if (speedBuffer.isFull() && (movingSpeed > data.getMaxSpeed())) {
|
||||
data.setMaxSpeed(movingSpeed);
|
||||
}
|
||||
} else {
|
||||
Log.d(MyTracksConstants.TAG,
|
||||
"TripStatistics ignoring big change: Raw Speed: " + speed
|
||||
+ " old: " + lastLocationSpeed + " [" + toString() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if this is a valid speed.
|
||||
*
|
||||
* @param updateTime The time at the current reading
|
||||
* @param speed The current speed
|
||||
* @param lastLocationTime The time at the last location
|
||||
* @param lastLocationSpeed Speed at the last location
|
||||
* @param speedBuffer A buffer of recent readings
|
||||
* @return True if this is likely a valid speed
|
||||
*/
|
||||
public static boolean isValidSpeed(long updateTime, double speed,
|
||||
long lastLocationTime, double lastLocationSpeed,
|
||||
DoubleBuffer speedBuffer) {
|
||||
|
||||
// We don't want to count 0 towards the speed.
|
||||
if (speed == 0) {
|
||||
return false;
|
||||
}
|
||||
// We are now sure the user is moving.
|
||||
long timeDifference = updateTime - lastLocationTime;
|
||||
|
||||
// There are a lot of noisy speed readings.
|
||||
// Do the cheapest checks first, most expensive last.
|
||||
// The following code will ignore unlikely to be real readings.
|
||||
// - 128 m/s seems to be an internal android error code.
|
||||
if (Math.abs(speed - 128) < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Another check for a spurious reading. See if the path seems physically
|
||||
// likely. Ignore any speeds that imply accelaration greater than 2g's
|
||||
// Really who can accelerate faster?
|
||||
double speedDifference = Math.abs(lastLocationSpeed - speed);
|
||||
if (speedDifference > MyTracksConstants.MAX_ACCELERATION * timeDifference) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There are three additional checks if the reading gets this far:
|
||||
// - Only use the speed if the buffer is full
|
||||
// - Check that the current speed is less than 10x the recent smoothed speed
|
||||
// - Double check that the current speed does not imply crazy acceleration
|
||||
double smoothedSpeed = speedBuffer.getAverage();
|
||||
double smoothedDiff = Math.abs(smoothedSpeed - speed);
|
||||
return !speedBuffer.isFull() ||
|
||||
(speed < smoothedSpeed * 10
|
||||
&& smoothedDiff < MyTracksConstants.MAX_ACCELERATION * timeDifference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the grade measurements.
|
||||
*
|
||||
* @param distance the distance the user just traveled
|
||||
* @param elevationDifference the elevation difference between the current
|
||||
* reading and the previous reading
|
||||
*/
|
||||
// @VisibleForTesting
|
||||
void updateGrade(double distance, double elevationDifference) {
|
||||
distanceBuffer.setNext(distance);
|
||||
double smoothedDistance = distanceBuffer.getAverage();
|
||||
|
||||
// With the error in the altitude measurement it is dangerous to divide
|
||||
// by anything less than 5.
|
||||
if (!elevationBuffer.isFull() || !distanceBuffer.isFull()
|
||||
|| smoothedDistance < 5.0) {
|
||||
return;
|
||||
}
|
||||
currentGrade = elevationDifference / smoothedDistance;
|
||||
gradeBuffer.setNext(currentGrade);
|
||||
data.updateGradeExtremities(gradeBuffer.getAverage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the track at the current time.
|
||||
*/
|
||||
public void pause() {
|
||||
pauseAt(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the track at the given time.
|
||||
*
|
||||
* @param time the time to pause at
|
||||
*/
|
||||
public void pauseAt(long time) {
|
||||
if (paused) { return; }
|
||||
|
||||
data.setStopTime(time);
|
||||
data.setTotalTime(time - data.getStartTime());
|
||||
lastLocation = null; // Make sure the counter restarts.
|
||||
paused = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the current track at the current time.
|
||||
*/
|
||||
public void resume() {
|
||||
resumeAt(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the current track at the given time.
|
||||
*
|
||||
* @param time the time to resume at
|
||||
*/
|
||||
public void resumeAt(long time) {
|
||||
if (!paused) { return; }
|
||||
|
||||
// TODO: The times are bogus if the track is paused then resumed again
|
||||
data.setStartTime(time);
|
||||
data.setStopTime(-1);
|
||||
paused = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TripStatistics { Data: " + data.toString()
|
||||
+ "; Total Locations: " + totalLocations
|
||||
+ "; Paused: " + paused
|
||||
+ "; Current speed: " + currentSpeed
|
||||
+ "; Current grade: " + currentGrade
|
||||
+ "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of time the user has been idle or 0 if they are moving.
|
||||
*/
|
||||
public long getIdleTime() {
|
||||
return lastLocation.getTime() - lastMovingLocation.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current elevation smoothed over several readings. The elevation
|
||||
* data is very noisy so it is better to use the smoothed elevation than the
|
||||
* raw elevation for many tasks.
|
||||
*
|
||||
* @return The elevation smoothed over several readings
|
||||
*/
|
||||
public double getSmoothedElevation() {
|
||||
return elevationBuffer.getAverage();
|
||||
}
|
||||
|
||||
public TripStatistics getStatistics() {
|
||||
// Take a snapshot - we do't want anyone messing with our internals
|
||||
return new TripStatistics(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,309 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.stats;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Statistical data about a trip.
|
||||
* The data in this class should be filled out by {@link TripStatistics}.
|
||||
*
|
||||
* TODO: Remove delegate methods from TripStatistics
|
||||
* (detail is getTotalTime)
|
||||
* TODO: Make Waypoint and Track use this instead of having the same fields
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class TripStatisticsData implements Parcelable {
|
||||
|
||||
/**
|
||||
* The start time for the trip. This is system time which might not match gps
|
||||
* time.
|
||||
*/
|
||||
long startTime;
|
||||
|
||||
/**
|
||||
* The total time that we believe the user was traveling in milliseconds.
|
||||
*/
|
||||
long movingTime;
|
||||
|
||||
/**
|
||||
* The total time of the trip in milliseconds.
|
||||
* This is only updated when new points are received, so it may be stale.
|
||||
*/
|
||||
long totalTime;
|
||||
|
||||
/**
|
||||
* The total distance in meters that the user traveled on this trip.
|
||||
*/
|
||||
double totalDistance;
|
||||
|
||||
/**
|
||||
* The total elevation gained on this trip in meters.
|
||||
*/
|
||||
double totalElevationGain;
|
||||
|
||||
/**
|
||||
* The maximum speed in meters/second reported that we believe to be a valid
|
||||
* speed.
|
||||
*/
|
||||
double maxSpeed;
|
||||
|
||||
/**
|
||||
* The current speed in meters/second as reported by the gps.
|
||||
*/
|
||||
double currentSpeed;
|
||||
|
||||
/**
|
||||
* The current grade. This value is very noisy and not reported to the user.
|
||||
*/
|
||||
double currentGrade;
|
||||
|
||||
/**
|
||||
* The min and max latitude values seen in this trip.
|
||||
*/
|
||||
final ExtremityMonitor latitudeExtremities = new ExtremityMonitor();
|
||||
|
||||
/**
|
||||
* The min and max longitude values seen in this trip.
|
||||
*/
|
||||
final ExtremityMonitor longitudeExtremities = new ExtremityMonitor();
|
||||
|
||||
/**
|
||||
* The min and max elevation seen on this trip in meters.
|
||||
*/
|
||||
final ExtremityMonitor elevationExtremities = new ExtremityMonitor();
|
||||
|
||||
/**
|
||||
* The minimum and maximum grade calculations on this trip.
|
||||
*/
|
||||
final ExtremityMonitor gradeExtremities = new ExtremityMonitor();
|
||||
|
||||
/**
|
||||
* Gets the time that this track started.
|
||||
*
|
||||
* @return The number of milliseconds since epoch to the time when this track
|
||||
* started
|
||||
*/
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total time that this track has been active.
|
||||
*
|
||||
* @return The total number of milliseconds the track was active
|
||||
*/
|
||||
public long getTotalTime() {
|
||||
return totalTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total distance the user traveled.
|
||||
*
|
||||
* @return The total distance traveled in meters
|
||||
*/
|
||||
public double getTotalDistance() {
|
||||
return totalDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the the maximum speed for this track.
|
||||
*
|
||||
* @return The maximum speed in m/s.
|
||||
*/
|
||||
public double getMaxSpeed() {
|
||||
return maxSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the the current speed for this track.
|
||||
*
|
||||
* @return The current speed in m/s
|
||||
*/
|
||||
public double getCurrentSpeed() {
|
||||
return currentSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the moving time.
|
||||
*
|
||||
* @return The total number of milliseconds the user was moving
|
||||
*/
|
||||
public long getMovingTime() {
|
||||
return movingTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total elevation gain for this trip. This is calculated as the sum
|
||||
* of all positive differences in the smoothed elevation.
|
||||
*
|
||||
* @return The elevation gain in meters for this trip
|
||||
*/
|
||||
public double getTotalElevationGain() {
|
||||
return totalElevationGain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current grade.
|
||||
*
|
||||
* @return The current grade
|
||||
*/
|
||||
public double getCurrentGrade() {
|
||||
return currentGrade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the leftmost position (lowest longitude) of the track.
|
||||
*/
|
||||
public int getLeft() {
|
||||
return (int) (longitudeExtremities.getMin() * 1E6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rightmost position (highest longitude) of the track.
|
||||
*/
|
||||
public int getRight() {
|
||||
return (int) (longitudeExtremities.getMax() * 1E6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bottommost position (lowest latitude) of the track.
|
||||
*/
|
||||
public int getBottom() {
|
||||
return (int) (latitudeExtremities.getMin() * 1E6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the topmost position (highest latitude) of the track.
|
||||
*/
|
||||
public int getTop() {
|
||||
return (int) (latitudeExtremities.getMax() * 1E6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum elevation seen on this trip. This is calculated from the
|
||||
* smoothed elevation so this can actually be more than the current elevation.
|
||||
*
|
||||
* @return The smallest elevation reading for this trip
|
||||
*/
|
||||
public double getMinElevation() {
|
||||
return elevationExtremities.getMin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum elevation seen on this trip. This is calculated from the
|
||||
* smoothed elevation so this can actually be less than the current elevation.
|
||||
*
|
||||
* @return The largest elevation reading for this trip
|
||||
*/
|
||||
public double getMaxElevation() {
|
||||
return elevationExtremities.getMax();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum grade for this trip.
|
||||
*
|
||||
* @return The maximum grade for this trip
|
||||
*/
|
||||
public double getMaxGrade() {
|
||||
return gradeExtremities.getMax();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum grade for this trip.
|
||||
*
|
||||
* @return The minimum grade for this trip
|
||||
*/
|
||||
public double getMinGrade() {
|
||||
return gradeExtremities.getMin();
|
||||
}
|
||||
|
||||
// Parcelable interface and creator
|
||||
|
||||
/**
|
||||
* Creator of statistics data from parcels.
|
||||
*/
|
||||
public static class Creator
|
||||
implements Parcelable.Creator<TripStatisticsData> {
|
||||
|
||||
@Override
|
||||
public TripStatisticsData createFromParcel(Parcel source) {
|
||||
TripStatisticsData data = new TripStatisticsData();
|
||||
|
||||
data.startTime = source.readLong();
|
||||
data.movingTime = source.readLong();
|
||||
data.totalTime = source.readLong();
|
||||
data.totalDistance = source.readDouble();
|
||||
data.totalElevationGain = source.readDouble();
|
||||
data.maxSpeed = source.readDouble();
|
||||
data.currentSpeed = source.readDouble();
|
||||
data.currentGrade = source.readDouble();
|
||||
|
||||
double minLat = source.readDouble();
|
||||
double maxLat = source.readDouble();
|
||||
data.latitudeExtremities.set(minLat, maxLat);
|
||||
|
||||
double minLong = source.readDouble();
|
||||
double maxLong = source.readDouble();
|
||||
data.longitudeExtremities.set(minLong, maxLong);
|
||||
|
||||
double minElev = source.readDouble();
|
||||
double maxElev = source.readDouble();
|
||||
data.elevationExtremities.set(minElev, maxElev);
|
||||
|
||||
double minGrade = source.readDouble();
|
||||
double maxGrade = source.readDouble();
|
||||
data.gradeExtremities.set(minGrade, maxGrade);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TripStatisticsData[] newArray(int size) {
|
||||
return new TripStatisticsData[size];
|
||||
}
|
||||
}
|
||||
|
||||
public static final Creator CREATOR = new Creator();
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(startTime);
|
||||
dest.writeLong(movingTime);
|
||||
dest.writeLong(totalTime);
|
||||
dest.writeDouble(totalDistance);
|
||||
dest.writeDouble(totalElevationGain);
|
||||
dest.writeDouble(maxSpeed);
|
||||
dest.writeDouble(currentSpeed);
|
||||
dest.writeDouble(currentGrade);
|
||||
|
||||
dest.writeDouble(latitudeExtremities.getMin());
|
||||
dest.writeDouble(latitudeExtremities.getMax());
|
||||
dest.writeDouble(longitudeExtremities.getMin());
|
||||
dest.writeDouble(longitudeExtremities.getMax());
|
||||
dest.writeDouble(elevationExtremities.getMin());
|
||||
dest.writeDouble(elevationExtremities.getMax());
|
||||
dest.writeDouble(gradeExtremities.getMin());
|
||||
dest.writeDouble(gradeExtremities.getMax());
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.util;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksSettings;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -82,18 +83,19 @@ public class ChartURLGenerator {
|
||||
}
|
||||
|
||||
// Round it up.
|
||||
TripStatistics stats = track.getStatistics();
|
||||
double effectiveMaxY = metricUnits
|
||||
? track.getMaxElevation()
|
||||
: track.getMaxElevation() * UnitConversions.M_TO_FT;
|
||||
? stats.getMaxElevation()
|
||||
: stats.getMaxElevation() * UnitConversions.M_TO_FT;
|
||||
effectiveMaxY = ((int) (effectiveMaxY / 100)) * 100 + 100;
|
||||
// Round it down.
|
||||
double effectiveMinY = 0;
|
||||
double minElevation = metricUnits
|
||||
? track.getMinElevation()
|
||||
: track.getMinElevation() * UnitConversions.M_TO_FT;
|
||||
? stats.getMinElevation()
|
||||
: stats.getMinElevation() * UnitConversions.M_TO_FT;
|
||||
|
||||
effectiveMinY = ((int) (minElevation / 100)) * 100;
|
||||
if (track.getMinElevation() < 0) {
|
||||
if (stats.getMinElevation() < 0) {
|
||||
effectiveMinY -= 100;
|
||||
}
|
||||
double ySpread = effectiveMaxY - effectiveMinY;
|
||||
@@ -108,7 +110,7 @@ public class ChartURLGenerator {
|
||||
|
||||
// Labels
|
||||
sb.append("&chxt=x,y");
|
||||
double distKM = track.getTotalDistance() / 1000.0;
|
||||
double distKM = stats.getTotalDistance() / 1000.0;
|
||||
double distDisplay =
|
||||
metricUnits ? distKM : (distKM * UnitConversions.KM_TO_MI);
|
||||
int xInterval = ((int) (distDisplay / 6));
|
||||
@@ -162,11 +164,11 @@ public class ChartURLGenerator {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected static double getNormalizedDistance(double d, Track track) {
|
||||
return d / track.getTotalDistance();
|
||||
private static double getNormalizedDistance(double d, Track track) {
|
||||
return d / track.getStatistics().getTotalDistance();
|
||||
}
|
||||
|
||||
protected static double getNormalizedElevation(
|
||||
private static double getNormalizedElevation(
|
||||
double d, double effectiveMinY, double ySpread) {
|
||||
return (d - effectiveMinY) / ySpread;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.google.android.apps.mytracks.util;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
|
||||
import com.google.android.maps.GeoPoint;
|
||||
|
||||
@@ -181,6 +182,7 @@ public class MyTracksUtils {
|
||||
Track piece = null;
|
||||
do {
|
||||
piece = new Track();
|
||||
TripStatistics pieceStats = piece.getStatistics();
|
||||
piece.setId(track.getId());
|
||||
piece.setName(track.getName());
|
||||
piece.setDescription(track.getDescription());
|
||||
@@ -191,8 +193,8 @@ public class MyTracksUtils {
|
||||
}
|
||||
int nPointsPiece = pieceLocations.size();
|
||||
if (nPointsPiece >= 2) {
|
||||
piece.setStartTime(pieceLocations.get(0).getTime());
|
||||
piece.setStopTime(pieceLocations.get(nPointsPiece - 1).getTime());
|
||||
pieceStats.setStartTime(pieceLocations.get(0).getTime());
|
||||
pieceStats.setStopTime(pieceLocations.get(nPointsPiece - 1).getTime());
|
||||
result.add(piece);
|
||||
}
|
||||
n += (pieceLocations.size() - 1);
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.google.android.apps.mytracks.MyTracksSettings;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.DescriptionGenerator;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -175,23 +176,24 @@ public class StringUtils implements DescriptionGenerator {
|
||||
preferences.getBoolean(MyTracksSettings.REPORT_SPEED, true);
|
||||
}
|
||||
|
||||
final double distanceInKm = track.getTotalDistance() / 1000;
|
||||
TripStatistics trackStats = track.getStatistics();
|
||||
final double distanceInKm = trackStats.getTotalDistance() / 1000;
|
||||
final double distanceInMiles = distanceInKm * UnitConversions.KM_TO_MI;
|
||||
final long minElevationInMeters = Math.round(track.getMinElevation());
|
||||
final long minElevationInMeters = Math.round(trackStats.getMinElevation());
|
||||
final long minElevationInFeet =
|
||||
Math.round(track.getMinElevation() * UnitConversions.M_TO_FT);
|
||||
final long maxElevationInMeters = Math.round(track.getMaxElevation());
|
||||
Math.round(trackStats.getMinElevation() * UnitConversions.M_TO_FT);
|
||||
final long maxElevationInMeters = Math.round(trackStats.getMaxElevation());
|
||||
final long maxElevationInFeet =
|
||||
Math.round(track.getMaxElevation() * UnitConversions.M_TO_FT);
|
||||
Math.round(trackStats.getMaxElevation() * UnitConversions.M_TO_FT);
|
||||
final long elevationGainInMeters =
|
||||
Math.round(track.getTotalElevationGain());
|
||||
final long elevationGainInFeet =
|
||||
Math.round(track.getTotalElevationGain() * UnitConversions.M_TO_FT);
|
||||
Math.round(trackStats.getTotalElevationGain());
|
||||
final long elevationGainInFeet = Math.round(
|
||||
trackStats.getTotalElevationGain() * UnitConversions.M_TO_FT);
|
||||
|
||||
long minGrade = 0;
|
||||
long maxGrade = 0;
|
||||
double trackMaxGrade = track.getMaxGrade();
|
||||
double trackMinGrade = track.getMinGrade();
|
||||
double trackMaxGrade = trackStats.getMaxGrade();
|
||||
double trackMinGrade = trackStats.getMinGrade();
|
||||
if (!Double.isNaN(trackMaxGrade)
|
||||
&& !Double.isInfinite(trackMaxGrade)) {
|
||||
maxGrade = Math.round(trackMaxGrade * 100);
|
||||
@@ -207,19 +209,19 @@ public class StringUtils implements DescriptionGenerator {
|
||||
}
|
||||
|
||||
String averageSpeed =
|
||||
getSpeedString(track.getAverageSpeed(),
|
||||
getSpeedString(trackStats.getAverageSpeed(),
|
||||
R.string.average_speed_label,
|
||||
R.string.average_pace_label,
|
||||
displaySpeed);
|
||||
|
||||
String averageMovingSpeed =
|
||||
getSpeedString(track.getAverageMovingSpeed(),
|
||||
getSpeedString(trackStats.getAverageMovingSpeed(),
|
||||
R.string.average_moving_speed_label,
|
||||
R.string.average_moving_pace_label,
|
||||
displaySpeed);
|
||||
|
||||
String maxSpeed =
|
||||
getSpeedString(track.getMaxSpeed(),
|
||||
getSpeedString(trackStats.getMaxSpeed(),
|
||||
R.string.max_speed_label,
|
||||
R.string.min_pace_label,
|
||||
displaySpeed);
|
||||
@@ -248,11 +250,11 @@ public class StringUtils implements DescriptionGenerator {
|
||||
|
||||
// Line 3
|
||||
context.getString(R.string.total_time_label),
|
||||
StringUtils.formatTime(track.getTotalTime()),
|
||||
StringUtils.formatTime(trackStats.getTotalTime()),
|
||||
|
||||
// Line 4
|
||||
context.getString(R.string.moving_time_label),
|
||||
StringUtils.formatTime(track.getMovingTime()),
|
||||
StringUtils.formatTime(trackStats.getMovingTime()),
|
||||
|
||||
// Line 5
|
||||
averageSpeed, averageMovingSpeed, maxSpeed,
|
||||
@@ -280,7 +282,7 @@ public class StringUtils implements DescriptionGenerator {
|
||||
|
||||
// Line 11
|
||||
context.getString(R.string.recorded_date),
|
||||
new Date(track.getStartTime()),
|
||||
new Date(trackStats.getStartTime()),
|
||||
|
||||
// Line 12
|
||||
context.getString(R.string.category), category,
|
||||
@@ -322,35 +324,39 @@ public class StringUtils implements DescriptionGenerator {
|
||||
* @return a track description
|
||||
*/
|
||||
public String generateWaypointDescription(Waypoint waypoint) {
|
||||
final double distanceInKm = waypoint.getTotalDistance() / 1000;
|
||||
TripStatistics stats = waypoint.getStatistics();
|
||||
|
||||
final double distanceInKm = stats.getTotalDistance() / 1000;
|
||||
final double distanceInMiles = distanceInKm * UnitConversions.KM_TO_MI;
|
||||
final double averageSpeedInKmh = waypoint.getAverageSpeed() * 3.6;
|
||||
final double averageSpeedInKmh = stats.getAverageSpeed() * 3.6;
|
||||
final double averageSpeedInMph =
|
||||
averageSpeedInKmh * UnitConversions.KMH_TO_MPH;
|
||||
final double movingSpeedInKmh = waypoint.getAverageMovingSpeed() * 3.6;
|
||||
final double movingSpeedInKmh = stats.getAverageMovingSpeed() * 3.6;
|
||||
final double movingSpeedInMph =
|
||||
movingSpeedInKmh * UnitConversions.KMH_TO_MPH;
|
||||
final double maxSpeedInKmh = waypoint.getMaxSpeed() * 3.6;
|
||||
final double maxSpeedInKmh = stats.getMaxSpeed() * 3.6;
|
||||
final double maxSpeedInMph = maxSpeedInKmh * UnitConversions.KMH_TO_MPH;
|
||||
final long minElevationInMeters = Math.round(waypoint.getMinElevation());
|
||||
final long minElevationInMeters = Math.round(stats.getMinElevation());
|
||||
final long minElevationInFeet =
|
||||
Math.round(waypoint.getMinElevation() * UnitConversions.M_TO_FT);
|
||||
final long maxElevationInMeters = Math.round(waypoint.getMaxElevation());
|
||||
Math.round(stats.getMinElevation() * UnitConversions.M_TO_FT);
|
||||
final long maxElevationInMeters = Math.round(stats.getMaxElevation());
|
||||
final long maxElevationInFeet =
|
||||
Math.round(waypoint.getMaxElevation() * UnitConversions.M_TO_FT);
|
||||
Math.round(stats.getMaxElevation() * UnitConversions.M_TO_FT);
|
||||
final long elevationGainInMeters =
|
||||
Math.round(waypoint.getTotalElevationGain());
|
||||
final long elevationGainInFeet = Math.round(waypoint.getTotalElevationGain()
|
||||
* UnitConversions.M_TO_FT);
|
||||
Math.round(stats.getTotalElevationGain());
|
||||
final long elevationGainInFeet = Math.round(
|
||||
stats.getTotalElevationGain() * UnitConversions.M_TO_FT);
|
||||
long theMinGrade = 0;
|
||||
long theMaxGrade = 0;
|
||||
if (!Double.isNaN(waypoint.getMaxGrade()) &&
|
||||
!Double.isInfinite(waypoint.getMaxGrade())) {
|
||||
theMaxGrade = Math.round(waypoint.getMaxGrade() * 100);
|
||||
double maxGrade = stats.getMaxGrade();
|
||||
double minGrade = stats.getMinGrade();
|
||||
if (!Double.isNaN(maxGrade) &&
|
||||
!Double.isInfinite(maxGrade)) {
|
||||
theMaxGrade = Math.round(maxGrade * 100);
|
||||
}
|
||||
if (!Double.isNaN(waypoint.getMinGrade()) &&
|
||||
!Double.isInfinite(waypoint.getMinGrade())) {
|
||||
theMinGrade = Math.round(waypoint.getMinGrade() * 100);
|
||||
if (!Double.isNaN(minGrade) &&
|
||||
!Double.isInfinite(minGrade)) {
|
||||
theMinGrade = Math.round(minGrade * 100);
|
||||
}
|
||||
final String percent = "%";
|
||||
|
||||
@@ -370,9 +376,9 @@ public class StringUtils implements DescriptionGenerator {
|
||||
distanceInKm, context.getString(R.string.kilometer),
|
||||
distanceInMiles, context.getString(R.string.mile),
|
||||
context.getString(R.string.time_label),
|
||||
StringUtils.formatTime(waypoint.getTotalTime()),
|
||||
StringUtils.formatTime(stats.getTotalTime()),
|
||||
context.getString(R.string.moving_time_label),
|
||||
StringUtils.formatTime(waypoint.getMovingTime()),
|
||||
StringUtils.formatTime(stats.getMovingTime()),
|
||||
context.getString(R.string.average_speed_label),
|
||||
averageSpeedInKmh, context.getString(R.string.kilometer_per_hour),
|
||||
averageSpeedInMph, context.getString(R.string.mile_per_hour),
|
||||
|
||||
+52
-45
@@ -9,24 +9,27 @@ import android.location.Location;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test the the function of the TripStatistics class.
|
||||
* Test the the function of the TripStatisticsBuilder class.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class TripStatisticsTest extends TestCase {
|
||||
public class TripStatisticsBuilderTest extends TestCase {
|
||||
|
||||
private TripStatistics stats = null;
|
||||
private TripStatisticsBuilder builder = null;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
stats = new TripStatistics();
|
||||
builder = new TripStatisticsBuilder();
|
||||
builder.resume();
|
||||
}
|
||||
|
||||
public void testAddLocationSimple() throws Exception {
|
||||
stats = new TripStatistics(1000);
|
||||
builder = new TripStatisticsBuilder();
|
||||
builder.resumeAt(1000);
|
||||
TripStatistics stats = builder.getStatistics();
|
||||
|
||||
assertEquals(0.0, stats.getSmoothedElevation());
|
||||
assertEquals(0.0, builder.getSmoothedElevation());
|
||||
assertEquals(Double.POSITIVE_INFINITY, stats.getMinElevation());
|
||||
assertEquals(Double.NEGATIVE_INFINITY, stats.getMaxElevation());
|
||||
assertEquals(0.0, stats.getMaxSpeed());
|
||||
@@ -48,19 +51,20 @@ public class TripStatisticsTest extends TestCase {
|
||||
// Each time slice is 10 seconds.
|
||||
long time = 1000 + 10000 * i;
|
||||
l.setTime(time);
|
||||
boolean moving = stats.addLocation(l, time);
|
||||
boolean moving = builder.addLocation(l, time);
|
||||
assertEquals((i != 0), moving);
|
||||
|
||||
stats = builder.getStatistics();
|
||||
assertEquals(10000 * i, stats.getTotalTime());
|
||||
System.out.println("i: " + i + "\nLocation: " + l + "\nStats: " + stats);
|
||||
assertEquals(10000 * i, stats.getMovingTime());
|
||||
assertEquals(i, stats.getSmoothedElevation(),
|
||||
assertEquals(i, builder.getSmoothedElevation(),
|
||||
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR / 2);
|
||||
assertEquals(0.0, stats.getMinElevation());
|
||||
assertEquals(i , stats.getMaxElevation(),
|
||||
assertEquals(i, stats.getMaxElevation(),
|
||||
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR / 2);
|
||||
assertEquals(i, stats.getTotalElevationGain(),
|
||||
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
|
||||
|
||||
if (i > MyTracksConstants.SPEED_SMOOTHING_FACTOR) {
|
||||
assertEquals(11.1f, stats.getMaxSpeed(), 0.1);
|
||||
}
|
||||
@@ -80,13 +84,15 @@ public class TripStatisticsTest extends TestCase {
|
||||
*/
|
||||
public void testElevationSimple() throws Exception {
|
||||
for (double elevation = 0; elevation < 1000; elevation += 10) {
|
||||
stats = new TripStatistics();
|
||||
builder = new TripStatisticsBuilder();
|
||||
builder.resume();
|
||||
for (int j = 0; j < 100; j++) {
|
||||
assertEquals(0.0, stats.updateElevation(elevation));
|
||||
assertEquals(elevation, stats.getSmoothedElevation());
|
||||
assertEquals(elevation, stats.getMinElevation());
|
||||
assertEquals(elevation, stats.getMaxElevation());
|
||||
assertEquals(0.0, stats.getTotalElevationGain());
|
||||
assertEquals(0.0, builder.updateElevation(elevation));
|
||||
assertEquals(elevation, builder.getSmoothedElevation());
|
||||
TripStatistics data = builder.getStatistics();
|
||||
assertEquals(elevation, data.getMinElevation());
|
||||
assertEquals(elevation, data.getMaxElevation());
|
||||
assertEquals(0.0, data.getTotalElevationGain());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,12 +108,13 @@ public class TripStatisticsTest extends TestCase {
|
||||
expectedGain = 1.0;
|
||||
}
|
||||
assertEquals(expectedGain,
|
||||
stats.updateElevation(i));
|
||||
assertEquals(i, stats.getSmoothedElevation(), 20);
|
||||
assertEquals(0.0, stats.getMinElevation(), 0.0);
|
||||
assertEquals(i, stats.getMaxElevation(),
|
||||
builder.updateElevation(i));
|
||||
assertEquals(i, builder.getSmoothedElevation(), 20);
|
||||
TripStatistics data = builder.getStatistics();
|
||||
assertEquals(0.0, data.getMinElevation(), 0.0);
|
||||
assertEquals(i, data.getMaxElevation(),
|
||||
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
|
||||
assertEquals(i, stats.getTotalElevationGain(),
|
||||
assertEquals(i, data.getTotalElevationGain(),
|
||||
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
|
||||
}
|
||||
}
|
||||
@@ -116,23 +123,23 @@ public class TripStatisticsTest extends TestCase {
|
||||
for (double i = 0; i < 1000; i++) {
|
||||
// The value of the elevation does not matter. This is just to fill the
|
||||
// buffer.
|
||||
stats.updateElevation(i);
|
||||
stats.updateGrade(100, 100);
|
||||
builder.updateElevation(i);
|
||||
builder.updateGrade(100, 100);
|
||||
if ((i > MyTracksConstants.GRADE_SMOOTHING_FACTOR)
|
||||
&& (i > MyTracksConstants.ELEVATION_SMOOTHING_FACTOR)) {
|
||||
assertEquals(1.0, stats.getMaxGrade());
|
||||
assertEquals(1.0, stats.getMinGrade());
|
||||
assertEquals(1.0, builder.getStatistics().getMaxGrade());
|
||||
assertEquals(1.0, builder.getStatistics().getMinGrade());
|
||||
}
|
||||
}
|
||||
for (double i = 0; i < 1000; i++) {
|
||||
// The value of the elevation does not matter. This is just to fill the
|
||||
// buffer.
|
||||
stats.updateElevation(i);
|
||||
stats.updateGrade(100, -100);
|
||||
builder.updateElevation(i);
|
||||
builder.updateGrade(100, -100);
|
||||
if ((i > MyTracksConstants.GRADE_SMOOTHING_FACTOR)
|
||||
&& (i > MyTracksConstants.ELEVATION_SMOOTHING_FACTOR)) {
|
||||
assertEquals(1.0, stats.getMaxGrade());
|
||||
assertEquals(-1.0, stats.getMinGrade());
|
||||
assertEquals(1.0, builder.getStatistics().getMaxGrade());
|
||||
assertEquals(-1.0, builder.getStatistics().getMinGrade());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,39 +148,39 @@ public class TripStatisticsTest extends TestCase {
|
||||
for (double i = 0; i < 100; i++) {
|
||||
// The value of the elevation does not matter. This is just to fill the
|
||||
// buffer.
|
||||
stats.updateElevation(i);
|
||||
stats.updateGrade(1, 100);
|
||||
assertEquals(Double.NEGATIVE_INFINITY, stats.getMaxGrade());
|
||||
assertEquals(Double.POSITIVE_INFINITY, stats.getMinGrade());
|
||||
builder.updateElevation(i);
|
||||
builder.updateGrade(1, 100);
|
||||
assertEquals(Double.NEGATIVE_INFINITY, builder.getStatistics().getMaxGrade());
|
||||
assertEquals(Double.POSITIVE_INFINITY, builder.getStatistics().getMinGrade());
|
||||
}
|
||||
}
|
||||
|
||||
public void testUpdateSpeedIncludeZero() {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
stats.updateSpeed(i + 1000, 0.0, i, 4.0);
|
||||
assertEquals(0.0, stats.getMaxSpeed());
|
||||
assertEquals((i + 1) * 1000, stats.getMovingTime());
|
||||
builder.updateSpeed(i + 1000, 0.0, i, 4.0);
|
||||
assertEquals(0.0, builder.getStatistics().getMaxSpeed());
|
||||
assertEquals((i + 1) * 1000, builder.getStatistics().getMovingTime());
|
||||
}
|
||||
}
|
||||
|
||||
public void testUpdateSpeedIngoreErrorCode() {
|
||||
stats.updateSpeed(12345000, 128.0, 12344000, 0.0);
|
||||
assertEquals(0.0, stats.getMaxSpeed());
|
||||
assertEquals(1000, stats.getMovingTime());
|
||||
builder.updateSpeed(12345000, 128.0, 12344000, 0.0);
|
||||
assertEquals(0.0, builder.getStatistics().getMaxSpeed());
|
||||
assertEquals(1000, builder.getStatistics().getMovingTime());
|
||||
}
|
||||
|
||||
public void testUpdateSpeedIngoreLargeAcceleration() {
|
||||
stats.updateSpeed(12345000, 100.0, 12344000, 1.0);
|
||||
assertEquals(0.0, stats.getMaxSpeed());
|
||||
assertEquals(1000, stats.getMovingTime());
|
||||
builder.updateSpeed(12345000, 100.0, 12344000, 1.0);
|
||||
assertEquals(0.0, builder.getStatistics().getMaxSpeed());
|
||||
assertEquals(1000, builder.getStatistics().getMovingTime());
|
||||
}
|
||||
|
||||
public void testUpdateSpeed() {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
stats.updateSpeed(i + 1000, 4.0, i, 4.0);
|
||||
assertEquals((i + 1) * 1000, stats.getMovingTime());
|
||||
builder.updateSpeed(i + 1000, 4.0, i, 4.0);
|
||||
assertEquals((i + 1) * 1000, builder.getStatistics().getMovingTime());
|
||||
if (i > MyTracksConstants.SPEED_SMOOTHING_FACTOR) {
|
||||
assertEquals(4.0, stats.getMaxSpeed());
|
||||
assertEquals(4.0, builder.getStatistics().getMaxSpeed());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
package com.google.android.apps.mytracks.util;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@@ -19,9 +20,10 @@ public class ChartURLGeneratorTest extends TestCase {
|
||||
Vector<Double> distances = new Vector<Double>();
|
||||
Vector<Double> elevations = new Vector<Double>();
|
||||
Track t = new Track();
|
||||
t.setMinElevation(0);
|
||||
t.setMaxElevation(2000);
|
||||
t.setTotalDistance(100);
|
||||
TripStatistics stats = t.getStatistics();
|
||||
stats.setMinElevation(0);
|
||||
stats.setMaxElevation(2000);
|
||||
stats.setTotalDistance(100);
|
||||
|
||||
distances.add(0.0);
|
||||
elevations.add(10.0);
|
||||
|
||||
Reference in New Issue
Block a user