Merge pull request #7317 from osmandapp/GpxStatisticImprovements
Fix #7054
This commit is contained in:
commit
ad50979f2f
8 changed files with 217 additions and 14 deletions
|
@ -159,12 +159,16 @@ public class GPXUtilities {
|
|||
public float distance;
|
||||
public int time;
|
||||
public float elevation;
|
||||
public boolean firstPoint = false;
|
||||
public boolean lastPoint = false;
|
||||
}
|
||||
|
||||
public static class Speed {
|
||||
public float distance;
|
||||
public int time;
|
||||
public float speed;
|
||||
public boolean firstPoint = false;
|
||||
public boolean lastPoint = false;
|
||||
}
|
||||
|
||||
public static class WptPt extends GPXExtensions {
|
||||
|
@ -355,15 +359,19 @@ public class GPXUtilities {
|
|||
|
||||
public static class GPXTrackAnalysis {
|
||||
public float totalDistance = 0;
|
||||
public float totalDistanceWithoutGaps = 0;
|
||||
public int totalTracks = 0;
|
||||
public long startTime = Long.MAX_VALUE;
|
||||
public long endTime = Long.MIN_VALUE;
|
||||
public long timeSpan = 0;
|
||||
public long timeSpanWithoutGaps = 0;
|
||||
//Next few lines for Issue 3222 heuristic testing only
|
||||
//public long timeMoving0 = 0;
|
||||
//public float totalDistanceMoving0 = 0;
|
||||
public long timeMoving = 0;
|
||||
public long timeMovingWithoutGaps = 0;
|
||||
public float totalDistanceMoving = 0;
|
||||
public float totalDistanceMovingWithoutGaps = 0;
|
||||
|
||||
public double diffElevationUp = 0;
|
||||
public double diffElevationDown = 0;
|
||||
|
@ -432,6 +440,10 @@ public class GPXUtilities {
|
|||
long startTimeOfSingleSegment = 0;
|
||||
long endTimeOfSingleSegment = 0;
|
||||
|
||||
float distanceOfSingleSegment = 0;
|
||||
float distanceMovingOfSingleSegment = 0;
|
||||
long timeMovingOfSingleSegment = 0;
|
||||
|
||||
float totalElevation = 0;
|
||||
int elevationPoints = 0;
|
||||
int speedCount = 0;
|
||||
|
@ -479,7 +491,7 @@ public class GPXUtilities {
|
|||
endTimeOfSingleSegment = time;
|
||||
}
|
||||
if (startTimeOfSingleSegment != 0 && endTimeOfSingleSegment != 0) {
|
||||
timeSpan += endTimeOfSingleSegment - startTimeOfSingleSegment;
|
||||
timeSpanWithoutGaps += endTimeOfSingleSegment - startTimeOfSingleSegment;
|
||||
startTimeOfSingleSegment = 0;
|
||||
endTimeOfSingleSegment = 0;
|
||||
}
|
||||
|
@ -627,6 +639,10 @@ public class GPXUtilities {
|
|||
if ((speed > 0) && (calculations[0] > 0.1 / 1000f * (point.time - prev.time)) && point.time != 0 && prev.time != 0) {
|
||||
timeMoving = timeMoving + (point.time - prev.time);
|
||||
totalDistanceMoving += calculations[0];
|
||||
if (s.segment.generalSegment && !point.firstPoint) {
|
||||
timeMovingOfSingleSegment += point.time - prev.time;
|
||||
distanceMovingOfSingleSegment += calculations[0];
|
||||
}
|
||||
}
|
||||
|
||||
//Next few lines for Issue 3222 heuristic testing only
|
||||
|
@ -658,6 +674,27 @@ public class GPXUtilities {
|
|||
if (!hasSpeedData && speed1.speed > 0 && totalDistance > 0) {
|
||||
hasSpeedData = true;
|
||||
}
|
||||
if (s.segment.generalSegment) {
|
||||
distanceOfSingleSegment += calculations[0];
|
||||
if (point.firstPoint) {
|
||||
distanceOfSingleSegment = 0;
|
||||
timeMovingOfSingleSegment = 0;
|
||||
distanceMovingOfSingleSegment = 0;
|
||||
if (j > 0) {
|
||||
elevation1.firstPoint = true;
|
||||
speed1.firstPoint = true;
|
||||
}
|
||||
}
|
||||
if (point.lastPoint) {
|
||||
totalDistanceWithoutGaps += distanceOfSingleSegment;
|
||||
timeMovingWithoutGaps += timeMovingOfSingleSegment;
|
||||
totalDistanceMovingWithoutGaps += distanceMovingOfSingleSegment;
|
||||
if (j < numberOfPoints - 1) {
|
||||
elevation1.lastPoint = true;
|
||||
speed1.lastPoint = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (totalDistance < 0) {
|
||||
|
|
|
@ -18,6 +18,35 @@
|
|||
android:layout_height="150dp"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/gpx_join_gaps_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/card_row_min_height"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/gpx_join_gaps_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding"
|
||||
android:text="@string/gpx_join_gaps"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
osmand:typeface="@string/font_roboto_regular" />
|
||||
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
android:id="@+id/gpx_join_gaps_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/average_range"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -18,6 +18,35 @@
|
|||
android:layout_height="150dp"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/gpx_join_gaps_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/card_row_min_height"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/gpx_join_gaps_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding"
|
||||
android:text="@string/gpx_join_gaps"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
osmand:typeface="@string/font_roboto_regular" />
|
||||
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
android:id="@+id/gpx_join_gaps_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/distance_time_span"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -18,6 +18,35 @@
|
|||
android:layout_height="150dp"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/gpx_join_gaps_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/card_row_min_height"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/gpx_join_gaps_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding"
|
||||
android:text="@string/gpx_join_gaps"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
osmand:typeface="@string/font_roboto_regular" />
|
||||
|
||||
<android.support.v7.widget.SwitchCompat
|
||||
android:id="@+id/gpx_join_gaps_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingRight="@dimen/content_padding" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/average_max"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
Thx - Hardy
|
||||
|
||||
-->
|
||||
<string name="gpx_join_gaps">Join gaps</string>
|
||||
<string name="app_mode_camper">Camper</string>
|
||||
<string name="app_mode_campervan">Campervan</string>
|
||||
<string name="rendering_attr_showLez_description">Show Low Emission zones on the map. Does not affect routing.</string>
|
||||
|
|
|
@ -197,6 +197,7 @@ public class GpxSelectionHelper {
|
|||
d = t.name + " " + d;
|
||||
}
|
||||
group.setDescription(d);
|
||||
group.setGeneralTrack(true);
|
||||
processGroupTrack(app, group);
|
||||
return group;
|
||||
}
|
||||
|
@ -215,6 +216,7 @@ public class GpxSelectionHelper {
|
|||
d = t.name + " " + d;
|
||||
}
|
||||
group.setDescription(d);
|
||||
group.setGeneralTrack(t.generalTrack);
|
||||
processGroupTrack(app, group);
|
||||
return group;
|
||||
}
|
||||
|
@ -771,6 +773,7 @@ public class GpxSelectionHelper {
|
|||
private double splitDistance = -1;
|
||||
private int splitTime = -1;
|
||||
private int color;
|
||||
private boolean generalTrack;
|
||||
|
||||
public GpxDisplayGroup(GPXFile gpx) {
|
||||
this.gpx = gpx;
|
||||
|
@ -878,6 +881,14 @@ public class GpxSelectionHelper {
|
|||
public void setColor(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public boolean isGeneralTrack() {
|
||||
return generalTrack;
|
||||
}
|
||||
|
||||
public void setGeneralTrack(boolean generalTrack) {
|
||||
this.generalTrack = generalTrack;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GpxDisplayItem {
|
||||
|
@ -903,5 +914,9 @@ public class GpxSelectionHelper {
|
|||
|
||||
public Matrix chartMatrix;
|
||||
public float chartHighlightPos = -1f;
|
||||
|
||||
public boolean isGeneralTrack() {
|
||||
return group != null && group.isGeneralTrack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1164,7 +1164,7 @@ public class GpxUiHelper {
|
|||
}
|
||||
|
||||
private static List<Entry> calculateElevationArray(GPXTrackAnalysis analysis, GPXDataSetAxisType axisType,
|
||||
float divX, float convEle) {
|
||||
float divX, float convEle, boolean useGeneralTrackPoints) {
|
||||
List<Entry> values = new ArrayList<>();
|
||||
List<Elevation> elevationData = analysis.elevationData;
|
||||
float nextX = 0;
|
||||
|
@ -1207,6 +1207,9 @@ public class GpxUiHelper {
|
|||
}
|
||||
hasSameY = false;
|
||||
}
|
||||
if (useGeneralTrackPoints && e.firstPoint && lastEntry != null) {
|
||||
values.add(new Entry(nextX, lastEntry.getY()));
|
||||
}
|
||||
prevElevOrig = e.elevation;
|
||||
prevElev = elev;
|
||||
nextY = elev * convEle;
|
||||
|
@ -1352,7 +1355,7 @@ public class GpxUiHelper {
|
|||
}
|
||||
});
|
||||
|
||||
List<Entry> values = calculateElevationArray(analysis, axisType, divX, convEle);
|
||||
List<Entry> values = calculateElevationArray(analysis, axisType, divX, convEle, true);
|
||||
|
||||
OrderedLineDataSet dataSet = new OrderedLineDataSet(values, "", GPXDataSetType.ALTITUDE, axisType);
|
||||
dataSet.priority = (float) (analysis.avgElevation - analysis.minElevation) * convEle;
|
||||
|
@ -1483,7 +1486,13 @@ public class GpxUiHelper {
|
|||
if (nextY < 0 || Float.isInfinite(nextY)) {
|
||||
nextY = 0;
|
||||
}
|
||||
if (s.firstPoint) {
|
||||
values.add(new Entry(nextX, 0));
|
||||
}
|
||||
values.add(new Entry(nextX, nextY));
|
||||
if (s.lastPoint) {
|
||||
values.add(new Entry(nextX, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1602,7 +1611,7 @@ public class GpxUiHelper {
|
|||
|
||||
List<Entry> values;
|
||||
if (eleValues == null) {
|
||||
values = calculateElevationArray(analysis, GPXDataSetAxisType.DISTANCE, 1f, 1f);
|
||||
values = calculateElevationArray(analysis, GPXDataSetAxisType.DISTANCE, 1f, 1f, false);
|
||||
} else {
|
||||
values = new ArrayList<>(eleValues.size());
|
||||
for (Entry e : eleValues) {
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.support.v4.view.MenuItemCompat;
|
|||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.SwitchCompat;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
@ -60,6 +61,7 @@ import net.osmand.plus.UiUtilities;
|
|||
import net.osmand.plus.activities.MapActivity;
|
||||
import net.osmand.plus.activities.TrackActivity;
|
||||
import net.osmand.plus.base.OsmAndListFragment;
|
||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||
import net.osmand.plus.helpers.GpxUiHelper;
|
||||
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetAxisType;
|
||||
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
|
||||
|
@ -91,6 +93,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
|
|||
|
||||
private boolean updateEnable;
|
||||
private boolean chartClicked;
|
||||
private boolean joinGapsEnabled;
|
||||
|
||||
private IconPopupMenu generalPopupMenu;
|
||||
private IconPopupMenu altitudePopupMenu;
|
||||
|
@ -455,7 +458,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
|
|||
dataSets.add(elevationDataSet);
|
||||
}
|
||||
if (analysis.hasElevationData) {
|
||||
List<Entry> eleValues = elevationDataSet != null ? elevationDataSet.getValues() : null;
|
||||
List<Entry> eleValues = elevationDataSet != null && !gpxItem.isGeneralTrack() ? elevationDataSet.getValues() : null;
|
||||
OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart,
|
||||
analysis, GPXDataSetAxisType.DISTANCE, eleValues, true, true);
|
||||
if (slopeDataSet != null) {
|
||||
|
@ -713,11 +716,17 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
|
|||
((ImageView) view.findViewById(R.id.end_time_icon))
|
||||
.setImageDrawable(ic.getThemedIcon(R.drawable.ic_action_time_end));
|
||||
|
||||
((TextView) view.findViewById(R.id.distance_text))
|
||||
.setText(OsmAndFormatter.getFormattedDistance(analysis.totalDistance, app));
|
||||
((TextView) view.findViewById(R.id.duration_text))
|
||||
.setText(Algorithms.formatDuration((int) (analysis.timeSpan / 1000), app.accessibilityEnabled()));
|
||||
|
||||
final SwitchCompat joinGapsSwitch = (SwitchCompat) view.findViewById(R.id.gpx_join_gaps_switch);
|
||||
joinGapsSwitch.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
joinGapsEnabled = joinGapsSwitch.isChecked();
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
View view = getViewAtPosition(i);
|
||||
updateJoinGapsInfo(view, i);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (analysis.timeSpan > 0) {
|
||||
DateFormat tf = SimpleDateFormat.getTimeInstance(DateFormat.SHORT);
|
||||
DateFormat df = SimpleDateFormat.getDateInstance(DateFormat.MEDIUM);
|
||||
|
@ -738,6 +747,7 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
|
|||
view.findViewById(R.id.list_divider).setVisibility(View.GONE);
|
||||
view.findViewById(R.id.start_end_time).setVisibility(View.GONE);
|
||||
}
|
||||
updateJoinGapsInfo(view, position);
|
||||
view.findViewById(R.id.analyze_on_map).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -844,12 +854,24 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
|
|||
((TextView) view.findViewById(R.id.ascent_text)).setText(asc);
|
||||
((TextView) view.findViewById(R.id.descent_text)).setText(desc);
|
||||
|
||||
final SwitchCompat joinGapsSwitch = (SwitchCompat) view.findViewById(R.id.gpx_join_gaps_switch);
|
||||
joinGapsSwitch.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
joinGapsEnabled = joinGapsSwitch.isChecked();
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
View view = getViewAtPosition(i);
|
||||
updateJoinGapsInfo(view, i);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
chart.setVisibility(View.GONE);
|
||||
view.findViewById(R.id.average_range).setVisibility(View.GONE);
|
||||
view.findViewById(R.id.list_divider).setVisibility(View.GONE);
|
||||
view.findViewById(R.id.ascent_descent).setVisibility(View.GONE);
|
||||
}
|
||||
updateJoinGapsInfo(view, position);
|
||||
view.findViewById(R.id.analyze_on_map).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -938,17 +960,25 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
|
|||
|
||||
((TextView) view.findViewById(R.id.average_text)).setText(avg);
|
||||
((TextView) view.findViewById(R.id.max_text)).setText(max);
|
||||
((TextView) view.findViewById(R.id.time_moving_text))
|
||||
.setText(Algorithms.formatDuration((int) (analysis.timeMoving / 1000), app.accessibilityEnabled()));
|
||||
((TextView) view.findViewById(R.id.distance_text))
|
||||
.setText(OsmAndFormatter.getFormattedDistance(analysis.totalDistanceMoving, app));
|
||||
|
||||
final SwitchCompat joinGapsSwitch = (SwitchCompat) view.findViewById(R.id.gpx_join_gaps_switch);
|
||||
joinGapsSwitch.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
joinGapsEnabled = joinGapsSwitch.isChecked();
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
View view = getViewAtPosition(i);
|
||||
updateJoinGapsInfo(view, i);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
chart.setVisibility(View.GONE);
|
||||
view.findViewById(R.id.average_max).setVisibility(View.GONE);
|
||||
view.findViewById(R.id.list_divider).setVisibility(View.GONE);
|
||||
view.findViewById(R.id.time_distance).setVisibility(View.GONE);
|
||||
}
|
||||
updateJoinGapsInfo(view, position);
|
||||
view.findViewById(R.id.analyze_on_map).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -1110,6 +1140,30 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
|
|||
}
|
||||
}
|
||||
|
||||
void updateJoinGapsInfo(View view, int position) {
|
||||
if (view != null) {
|
||||
GPXTrackAnalysis analysis = gpxItem.analysis;
|
||||
AndroidUiHelper.updateVisibility(view.findViewById(R.id.gpx_join_gaps_container), gpxItem.isGeneralTrack() && analysis != null);
|
||||
((SwitchCompat) view.findViewById(R.id.gpx_join_gaps_switch)).setChecked(joinGapsEnabled);
|
||||
if (analysis != null) {
|
||||
GPXTabItemType tabType = tabTypes[position];
|
||||
if (tabType.equals(GPXTabItemType.GPX_TAB_ITEM_GENERAL)) {
|
||||
float totalDistance = joinGapsEnabled && gpxItem.isGeneralTrack() ? analysis.totalDistanceWithoutGaps : analysis.totalDistance;
|
||||
float timeSpan = joinGapsEnabled && gpxItem.isGeneralTrack() ? analysis.timeSpanWithoutGaps : analysis.timeSpan;
|
||||
|
||||
((TextView) view.findViewById(R.id.distance_text)).setText(OsmAndFormatter.getFormattedDistance(totalDistance, app));
|
||||
((TextView) view.findViewById(R.id.duration_text)).setText(Algorithms.formatDuration((int) (timeSpan / 1000), app.accessibilityEnabled()));
|
||||
} else if (tabType.equals(GPXTabItemType.GPX_TAB_ITEM_SPEED)) {
|
||||
long timeMoving = joinGapsEnabled && gpxItem.isGeneralTrack() ? analysis.timeMovingWithoutGaps : analysis.timeMoving;
|
||||
float totalDistanceMoving = joinGapsEnabled && gpxItem.isGeneralTrack() ? analysis.totalDistanceMovingWithoutGaps : analysis.totalDistanceMoving;
|
||||
|
||||
((TextView) view.findViewById(R.id.time_moving_text)).setText(Algorithms.formatDuration((int) (timeMoving / 1000), app.accessibilityEnabled()));
|
||||
((TextView) view.findViewById(R.id.distance_text)).setText(OsmAndFormatter.getFormattedDistance(totalDistanceMoving, app));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateChart(LineChart chart) {
|
||||
if (chart != null && !chart.isEmpty()) {
|
||||
if (gpxItem.chartMatrix != null) {
|
||||
|
|
Loading…
Reference in a new issue