Optimize charts. Turn off splines.
This commit is contained in:
parent
69399b12c9
commit
0e920b7f91
3 changed files with 228 additions and 269 deletions
|
@ -225,16 +225,20 @@ public class ShowRouteInfoDialogFragment extends DialogFragment {
|
||||||
});
|
});
|
||||||
|
|
||||||
GPXTrackAnalysis analysis = gpx.getAnalysis(0);
|
GPXTrackAnalysis analysis = gpx.getAnalysis(0);
|
||||||
List<ILineDataSet> dataSets = new ArrayList<>();
|
if (analysis.totalDistance > 0) {
|
||||||
GpxUiHelper.OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, mChart, analysis, false, true);
|
List<ILineDataSet> dataSets = new ArrayList<>();
|
||||||
dataSets.add(elevationDataSet);
|
GpxUiHelper.OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, mChart, analysis, false, true);
|
||||||
if (analysis.elevationData.size() > 1) {
|
dataSets.add(elevationDataSet);
|
||||||
GpxUiHelper.OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, mChart, analysis, true, true);
|
if (analysis.elevationData.size() > 1) {
|
||||||
dataSets.add(slopeDataSet);
|
GpxUiHelper.OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, mChart, analysis, elevationDataSet.getValues(), true, true);
|
||||||
|
dataSets.add(slopeDataSet);
|
||||||
|
}
|
||||||
|
LineData data = new LineData(dataSets);
|
||||||
|
mChart.setData(data);
|
||||||
|
mChart.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
mChart.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
LineData data = new LineData(dataSets);
|
|
||||||
mChart.setData(data);
|
|
||||||
|
|
||||||
((TextView) headerView.findViewById(R.id.average_text))
|
((TextView) headerView.findViewById(R.id.average_text))
|
||||||
.setText(OsmAndFormatter.getFormattedAlt(analysis.avgElevation, app));
|
.setText(OsmAndFormatter.getFormattedAlt(analysis.avgElevation, app));
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
@ -34,6 +36,7 @@ import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.github.mikephil.charting.animation.ChartAnimator;
|
||||||
import com.github.mikephil.charting.charts.LineChart;
|
import com.github.mikephil.charting.charts.LineChart;
|
||||||
import com.github.mikephil.charting.components.AxisBase;
|
import com.github.mikephil.charting.components.AxisBase;
|
||||||
import com.github.mikephil.charting.components.Legend;
|
import com.github.mikephil.charting.components.Legend;
|
||||||
|
@ -46,10 +49,14 @@ import com.github.mikephil.charting.data.LineData;
|
||||||
import com.github.mikephil.charting.data.LineDataSet;
|
import com.github.mikephil.charting.data.LineDataSet;
|
||||||
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
|
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
|
||||||
import com.github.mikephil.charting.formatter.IFillFormatter;
|
import com.github.mikephil.charting.formatter.IFillFormatter;
|
||||||
|
import com.github.mikephil.charting.formatter.IValueFormatter;
|
||||||
import com.github.mikephil.charting.highlight.Highlight;
|
import com.github.mikephil.charting.highlight.Highlight;
|
||||||
import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider;
|
import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider;
|
||||||
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
|
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
|
||||||
|
import com.github.mikephil.charting.renderer.LineChartRenderer;
|
||||||
import com.github.mikephil.charting.utils.MPPointF;
|
import com.github.mikephil.charting.utils.MPPointF;
|
||||||
|
import com.github.mikephil.charting.utils.Transformer;
|
||||||
|
import com.github.mikephil.charting.utils.ViewPortHandler;
|
||||||
|
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.CallbackWithObject;
|
import net.osmand.CallbackWithObject;
|
||||||
|
@ -867,6 +874,8 @@ public class GpxUiHelper {
|
||||||
mChart.setExtraTopOffset(24f);
|
mChart.setExtraTopOffset(24f);
|
||||||
mChart.setExtraBottomOffset(16f);
|
mChart.setExtraBottomOffset(16f);
|
||||||
|
|
||||||
|
mChart.setRenderer(new SplineRenderer(mChart, mChart.getAnimator(), mChart.getViewPortHandler()));
|
||||||
|
|
||||||
// create a custom MarkerView (extend MarkerView) and specify the layout
|
// create a custom MarkerView (extend MarkerView) and specify the layout
|
||||||
// to use for it
|
// to use for it
|
||||||
GPXMarkerView mv = new GPXMarkerView(mChart.getContext());
|
GPXMarkerView mv = new GPXMarkerView(mChart.getContext());
|
||||||
|
@ -969,6 +978,54 @@ public class GpxUiHelper {
|
||||||
return granularity;
|
return granularity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<Entry> calculateElevationArray(GPXTrackAnalysis analysis, float divX, float convEle) {
|
||||||
|
List<Entry> values = new ArrayList<>();
|
||||||
|
List<Elevation> elevationData = analysis.elevationData;
|
||||||
|
float nextX = 0;
|
||||||
|
float nextY;
|
||||||
|
float prevYM;
|
||||||
|
float elev;
|
||||||
|
float prevElevOrig = -80000;
|
||||||
|
float prevElev = 0;
|
||||||
|
int i = -1;
|
||||||
|
int lastIndex = elevationData.size() - 1;
|
||||||
|
float shift = 0f;
|
||||||
|
Entry lastEntry = null;
|
||||||
|
float lastXSameY = -1;
|
||||||
|
boolean hasSameY = false;
|
||||||
|
for (Elevation e : elevationData) {
|
||||||
|
i++;
|
||||||
|
if (e.distance > 0) {
|
||||||
|
nextX += (float) e.distance / divX;
|
||||||
|
elev = (float) e.elevation;
|
||||||
|
if (prevElevOrig != -80000) {
|
||||||
|
if (elev > prevElevOrig) {
|
||||||
|
elev -= 1f;
|
||||||
|
} else if (prevElevOrig == elev && i < lastIndex) {
|
||||||
|
hasSameY = true;
|
||||||
|
lastXSameY = nextX;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (prevElev == elev && i < lastIndex) {
|
||||||
|
hasSameY = true;
|
||||||
|
lastXSameY = nextX;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (hasSameY) {
|
||||||
|
values.add(new Entry(lastXSameY, lastEntry.getY()));
|
||||||
|
}
|
||||||
|
hasSameY = false;
|
||||||
|
}
|
||||||
|
prevElevOrig = (float) e.elevation;
|
||||||
|
prevElev = elev;
|
||||||
|
nextY = elev * convEle;
|
||||||
|
lastEntry = new Entry(nextX, nextY);
|
||||||
|
values.add(lastEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
public static OrderedLineDataSet createGPXElevationDataSet(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis, boolean drawFilled) {
|
public static OrderedLineDataSet createGPXElevationDataSet(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis, boolean drawFilled) {
|
||||||
OsmandSettings settings = ctx.getSettings();
|
OsmandSettings settings = ctx.getSettings();
|
||||||
OsmandSettings.MetricsConstants mc = settings.METRIC_SYSTEM.get();
|
OsmandSettings.MetricsConstants mc = settings.METRIC_SYSTEM.get();
|
||||||
|
@ -1020,76 +1077,7 @@ public class GpxUiHelper {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
List<Entry> values = new ArrayList<>();
|
List<Entry> values = calculateElevationArray(analysis, divX, convEle);
|
||||||
List<Elevation> elevationData = analysis.elevationData;
|
|
||||||
float nextX = 0;
|
|
||||||
float nextY;
|
|
||||||
float elev;
|
|
||||||
float prevElev = -80000;
|
|
||||||
int i = -1;
|
|
||||||
int lastIndex = elevationData.size() - 1;
|
|
||||||
float shift = 0f;
|
|
||||||
Entry entry = null;
|
|
||||||
for (Elevation e : elevationData) {
|
|
||||||
i++;
|
|
||||||
if (e.distance > 0) {
|
|
||||||
nextX += (float) e.distance / divX;
|
|
||||||
elev = (float) e.elevation;
|
|
||||||
if (prevElev != -80000) {
|
|
||||||
if (elev < prevElev) {
|
|
||||||
shift = 0f;
|
|
||||||
} else if (elev > prevElev) {
|
|
||||||
shift = -1f;
|
|
||||||
} else if (prevElev == elev && i < lastIndex) {
|
|
||||||
values.add(new Entry(nextX, entry.getY()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prevElev = elev;
|
|
||||||
nextY = (elev + shift) * convEle;
|
|
||||||
entry = new Entry(nextX, nextY);
|
|
||||||
values.add(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
List<Entry> newValues = new ArrayList<>();
|
|
||||||
Entry lastEntry = null;
|
|
||||||
i = -1;
|
|
||||||
lastIndex = values.size() - 1;
|
|
||||||
boolean hasSameY = false;
|
|
||||||
for (Entry e : values) {
|
|
||||||
i++;
|
|
||||||
if (lastEntry != null) {
|
|
||||||
if (lastEntry.getY() == e.getY() && i < lastIndex) {
|
|
||||||
hasSameY = true;
|
|
||||||
continue;
|
|
||||||
} else if (hasSameY) {
|
|
||||||
lastEntry.setX(lastEntry.getX() + (e.getX() - lastEntry.getX()) / 2f);
|
|
||||||
hasSameY = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newValues.add(e);
|
|
||||||
lastEntry = e;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
List<Point2D> points = new ArrayList<>(values.size());
|
|
||||||
for (Entry e : values) {
|
|
||||||
points.add(new Point2D(e.getX(), e.getY()));
|
|
||||||
}
|
|
||||||
List<Segment> spline = calculateSpline(points);
|
|
||||||
if (spline != null) {
|
|
||||||
int count = 8;
|
|
||||||
values = new ArrayList<>();
|
|
||||||
for (Segment s : spline) {
|
|
||||||
Point2D p = new Point2D();
|
|
||||||
for (i = 0; i < count; ++i) {
|
|
||||||
s.calc((double) i / (double) count, p);
|
|
||||||
values.add(new Entry((float) p.x, (float) p.y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OrderedLineDataSet dataSet = new OrderedLineDataSet(values, "", GPXDataSetType.ALTITUDE);
|
OrderedLineDataSet dataSet = new OrderedLineDataSet(values, "", GPXDataSetType.ALTITUDE);
|
||||||
dataSet.priority = (float) (analysis.avgElevation - analysis.minElevation) * convEle;
|
dataSet.priority = (float) (analysis.avgElevation - analysis.minElevation) * convEle;
|
||||||
|
@ -1118,7 +1106,7 @@ public class GpxUiHelper {
|
||||||
dataSet.setDrawHorizontalHighlightIndicator(false);
|
dataSet.setDrawHorizontalHighlightIndicator(false);
|
||||||
dataSet.setHighLightColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
dataSet.setHighLightColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
||||||
|
|
||||||
//dataSet.setCubicIntensity(.2f);
|
//dataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
|
||||||
//dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
|
//dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
|
||||||
|
|
||||||
dataSet.setFillFormatter(new IFillFormatter() {
|
dataSet.setFillFormatter(new IFillFormatter() {
|
||||||
|
@ -1271,16 +1259,19 @@ public class GpxUiHelper {
|
||||||
mChart.setData(data);
|
mChart.setData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OrderedLineDataSet createGPXSlopeDataSet(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis, boolean drawFilled) {
|
public static OrderedLineDataSet createGPXSlopeDataSet(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, List<Entry> eleValues, boolean useRightAxis, boolean drawFilled) {
|
||||||
OsmandSettings settings = ctx.getSettings();
|
OsmandSettings settings = ctx.getSettings();
|
||||||
boolean light = settings.isLightContent();
|
boolean light = settings.isLightContent();
|
||||||
final float meters = analysis.totalDistance;
|
OsmandSettings.MetricsConstants mc = settings.METRIC_SYSTEM.get();
|
||||||
|
boolean useFeet = (mc == OsmandSettings.MetricsConstants.MILES_AND_FEET) || (mc == OsmandSettings.MetricsConstants.MILES_AND_YARDS);
|
||||||
|
final float convEle = useFeet ? 3.28084f : 1.0f;
|
||||||
|
final float totalDistance = analysis.totalDistance;
|
||||||
|
|
||||||
float[] koef = new float[] { 1f };
|
float[] koef = new float[] { 1f };
|
||||||
StringBuilder fmt = new StringBuilder();
|
StringBuilder fmt = new StringBuilder();
|
||||||
StringBuilder unitX = new StringBuilder();
|
StringBuilder unitX = new StringBuilder();
|
||||||
|
|
||||||
float granularity = getXAxisParams(ctx, meters, koef, fmt, unitX);
|
float granularity = getXAxisParams(ctx, totalDistance, koef, fmt, unitX);
|
||||||
float divX = koef[0];
|
float divX = koef[0];
|
||||||
final String formatX = fmt.toString();
|
final String formatX = fmt.toString();
|
||||||
final String mainUnitX = unitX.toString();
|
final String mainUnitX = unitX.toString();
|
||||||
|
@ -1319,174 +1310,21 @@ public class GpxUiHelper {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
List<Entry> values;
|
||||||
List<Entry> values = new ArrayList<>();
|
if (eleValues == null) {
|
||||||
List<Elevation> elevationData = analysis.elevationData;
|
values = calculateElevationArray(analysis, 1f, 1f);
|
||||||
float nextX = 0;
|
} else {
|
||||||
float nextY;
|
values = new ArrayList<>(eleValues.size());
|
||||||
float elev;
|
for (Entry e : eleValues) {
|
||||||
float prevElev = -80000;
|
values.add(new Entry(e.getX() * divX, e.getY() / convEle));
|
||||||
int i = -1;
|
|
||||||
int lastIndex = elevationData.size() - 1;
|
|
||||||
float shift = 0f;
|
|
||||||
Entry entry = null;
|
|
||||||
for (Elevation e : elevationData) {
|
|
||||||
i++;
|
|
||||||
if (e.distance > 0) {
|
|
||||||
nextX += (float) e.distance / divX;
|
|
||||||
elev = (float) e.elevation;
|
|
||||||
nextY = elev + shift;
|
|
||||||
entry = new Entry(nextX, nextY);
|
|
||||||
values.add(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
List<Entry> values = new ArrayList<>();
|
|
||||||
List<Elevation> elevationData = analysis.elevationData;
|
|
||||||
float nextX = 0;
|
|
||||||
float nextY;
|
|
||||||
float elev;
|
|
||||||
float prevElev = -80000;
|
|
||||||
int i = -1;
|
|
||||||
int lastIndex = elevationData.size() - 1;
|
|
||||||
float shift = 0f;
|
|
||||||
Entry entry = null;
|
|
||||||
for (Elevation e : elevationData) {
|
|
||||||
i++;
|
|
||||||
if (e.distance > 0) {
|
|
||||||
nextX += (float) e.distance;
|
|
||||||
elev = (float) e.elevation;
|
|
||||||
if (prevElev != -80000) {
|
|
||||||
if (elev < prevElev) {
|
|
||||||
shift = 0f;
|
|
||||||
} else if (elev > prevElev) {
|
|
||||||
shift = -1f;
|
|
||||||
} else if (prevElev == elev && i < lastIndex) {
|
|
||||||
values.add(new Entry(nextX, entry.getY()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prevElev = elev;
|
|
||||||
nextY = (elev + shift);
|
|
||||||
entry = new Entry(nextX, nextY);
|
|
||||||
values.add(entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (values == null) {
|
||||||
List<Entry> eleValues = new ArrayList<>();
|
return null;
|
||||||
Entry lastEntry = null;
|
|
||||||
i = -1;
|
|
||||||
lastIndex = values.size() - 1;
|
|
||||||
boolean hasSameY = false;
|
|
||||||
for (Entry e : values) {
|
|
||||||
i++;
|
|
||||||
if (lastEntry != null) {
|
|
||||||
if (lastEntry.getY() == e.getY() && i < lastIndex) {
|
|
||||||
hasSameY = true;
|
|
||||||
continue;
|
|
||||||
} else if (hasSameY) {
|
|
||||||
lastEntry.setX(lastEntry.getX() + (e.getX() - lastEntry.getX()) / 2f);
|
|
||||||
hasSameY = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eleValues.add(e);
|
|
||||||
lastEntry = e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Point2D> points = new ArrayList<>(eleValues.size());
|
int lastIndex = values.size() - 1;
|
||||||
for (Entry e : eleValues) {
|
|
||||||
points.add(new Point2D(e.getX(), e.getY()));
|
|
||||||
}
|
|
||||||
List<Segment> spline = calculateSpline(points);
|
|
||||||
if (spline != null) {
|
|
||||||
int count = 8;
|
|
||||||
eleValues = new ArrayList<>();
|
|
||||||
for (Segment s : spline) {
|
|
||||||
Point2D p = new Point2D();
|
|
||||||
for (i = 0; i < count; ++i) {
|
|
||||||
s.calc((double) i / (double) count, p);
|
|
||||||
eleValues.add(new Entry((float) p.x, (float) p.y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
values.clear();
|
|
||||||
//List<Elevation> elevationData = analysis.elevationData;
|
|
||||||
//float nextX;
|
|
||||||
//float nextY;
|
|
||||||
float nextXM;
|
|
||||||
float nextYM;
|
|
||||||
float prevXM;
|
|
||||||
float prevYM;
|
|
||||||
float delta = 150;
|
|
||||||
float prevDistM = -1;
|
|
||||||
float nextDistM;
|
|
||||||
float d;
|
|
||||||
if (eleValues.size() > 1) {
|
|
||||||
nextXM = eleValues.get(0).getX();
|
|
||||||
nextYM = eleValues.get(0).getY();
|
|
||||||
prevXM = nextXM;
|
|
||||||
prevYM = 0;
|
|
||||||
nextX = 0;
|
|
||||||
nextY = 0;
|
|
||||||
for (i = 1; i < eleValues.size(); i++) {
|
|
||||||
Entry e = eleValues.get(i);
|
|
||||||
d = e.getX() - prevXM;
|
|
||||||
if (d < delta && i < eleValues.size() - 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (prevDistM < 0) {
|
|
||||||
nextDistM = d / 2f;
|
|
||||||
} else {
|
|
||||||
nextDistM = prevDistM / 2f + d / 2f;
|
|
||||||
}
|
|
||||||
prevDistM = d;
|
|
||||||
if (nextX == 0) {
|
|
||||||
values.add(new Entry(prevXM / divX, 0));
|
|
||||||
prevXM = nextXM;
|
|
||||||
prevYM = nextYM;
|
|
||||||
}
|
|
||||||
nextXM = e.getX();
|
|
||||||
nextYM = e.getY();
|
|
||||||
nextX = (prevXM + nextDistM) / divX;
|
|
||||||
nextY = (nextYM - prevYM) / (nextXM - prevXM) * 100f;
|
|
||||||
if (Math.abs(nextY) < 120) {
|
|
||||||
values.add(new Entry(nextX, nextY));
|
|
||||||
prevXM = nextXM;
|
|
||||||
prevYM = nextYM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
points = new ArrayList<>(values.size());
|
|
||||||
for (Entry e : values) {
|
|
||||||
points.add(new Point2D(e.getX(), e.getY()));
|
|
||||||
}
|
|
||||||
spline = calculateSpline(points);
|
|
||||||
if (spline != null) {
|
|
||||||
int count = 8;
|
|
||||||
values = new ArrayList<>();
|
|
||||||
for (Segment s : spline) {
|
|
||||||
Point2D p = new Point2D();
|
|
||||||
for (i = 0; i < count; ++i) {
|
|
||||||
s.calc((double) i / (double) count, p);
|
|
||||||
values.add(new Entry((float) p.x, (float) p.y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
double totalDistance = meters;
|
|
||||||
double[] dist = new double[values.size()];
|
|
||||||
double[] h = new double[values.size()];
|
|
||||||
i = 0;
|
|
||||||
for (Entry e : values) {
|
|
||||||
dist[i] = e.getX();
|
|
||||||
h[i] = e.getY();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
double STEP = 5;
|
double STEP = 5;
|
||||||
|
|
||||||
|
@ -1497,34 +1335,56 @@ public class GpxUiHelper {
|
||||||
if (k > 0) {
|
if (k > 0) {
|
||||||
calculatedDist[k] = calculatedDist[k - 1] + STEP;
|
calculatedDist[k] = calculatedDist[k - 1] + STEP;
|
||||||
}
|
}
|
||||||
while(nextW < lastIndex && calculatedDist[k] > dist[nextW]) {
|
while(nextW < lastIndex && calculatedDist[k] > values.get(nextW).getX()) {
|
||||||
nextW ++;
|
nextW ++;
|
||||||
}
|
}
|
||||||
double pd = nextW == 0 ? 0 : dist[nextW - 1];
|
double pd = nextW == 0 ? 0 : values.get(nextW - 1).getX();
|
||||||
double ph = nextW == 0 ? h[0] : h[nextW - 1];
|
double ph = nextW == 0 ? values.get(0).getY() : values.get(nextW - 1).getY();
|
||||||
calculatedH[k] = ph + (h[nextW] - ph) / (dist[nextW] - pd) * (calculatedDist[k] - pd);
|
calculatedH[k] = ph + (values.get(nextW).getY() - ph) / (values.get(nextW).getX() - pd) * (calculatedDist[k] - pd);
|
||||||
}
|
}
|
||||||
|
|
||||||
double GREEN_PROXIMITY = 150;
|
double SLOPE_PROXIMITY = 150;
|
||||||
|
|
||||||
double[] calculatedGreenDist = new double[(int) ((totalDistance - GREEN_PROXIMITY) / STEP) + 1];
|
double[] calculatedSlopeDist = new double[(int) ((totalDistance - SLOPE_PROXIMITY) / STEP) + 1];
|
||||||
double[] calculatedGreenH = new double[(int) ((totalDistance - GREEN_PROXIMITY) / STEP) + 1];
|
double[] calculatedSlope = new double[(int) ((totalDistance - SLOPE_PROXIMITY) / STEP) + 1];
|
||||||
|
|
||||||
int index = (int) ((GREEN_PROXIMITY / STEP) / 2);
|
int index = (int) ((SLOPE_PROXIMITY / STEP) / 2);
|
||||||
for (int k = 0; k < calculatedGreenDist.length; k++) {
|
for (int k = 0; k < calculatedSlopeDist.length; k++) {
|
||||||
calculatedGreenDist[k] = calculatedDist[index + k];
|
calculatedSlopeDist[k] = calculatedDist[index + k];
|
||||||
calculatedGreenH[k] = (calculatedH[ 2 * index + k] - calculatedH[k]) * 100 / GREEN_PROXIMITY;
|
calculatedSlope[k] = (calculatedH[ 2 * index + k] - calculatedH[k]) * 100 / SLOPE_PROXIMITY;
|
||||||
if (Double.isNaN(calculatedGreenH[k])) {
|
if (Double.isNaN(calculatedSlope[k])) {
|
||||||
calculatedGreenH[k] = 0;
|
calculatedSlope[k] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
values.clear();
|
List<Entry> slopeValues = new ArrayList<>(calculatedSlopeDist.length);
|
||||||
for (i = 0; i < calculatedGreenDist.length; i++) {
|
float prevSlope = -80000;
|
||||||
values.add(new Entry((float) calculatedGreenDist[i] / divX, (float) calculatedGreenH[i]));
|
float slope;
|
||||||
|
float x;
|
||||||
|
float lastXSameY = 0;
|
||||||
|
boolean hasSameY = false;
|
||||||
|
Entry lastEntry = null;
|
||||||
|
lastIndex = calculatedSlopeDist.length - 1;
|
||||||
|
for (int i = 0; i < calculatedSlopeDist.length; i++) {
|
||||||
|
x = (float) calculatedSlopeDist[i] / divX;
|
||||||
|
slope = (float) calculatedSlope[i];
|
||||||
|
if (prevSlope != -80000) {
|
||||||
|
if (prevSlope == slope && i < lastIndex) {
|
||||||
|
hasSameY = true;
|
||||||
|
lastXSameY = x;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (hasSameY) {
|
||||||
|
slopeValues.add(new Entry(lastXSameY, lastEntry.getY()));
|
||||||
|
}
|
||||||
|
hasSameY = false;
|
||||||
|
}
|
||||||
|
prevSlope = slope;
|
||||||
|
lastEntry = new Entry(x, slope);
|
||||||
|
slopeValues.add(lastEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
OrderedLineDataSet dataSet = new OrderedLineDataSet(values, "", GPXDataSetType.SLOPE);
|
OrderedLineDataSet dataSet = new OrderedLineDataSet(slopeValues, "", GPXDataSetType.SLOPE);
|
||||||
dataSet.units = mainUnitY;
|
dataSet.units = mainUnitY;
|
||||||
|
|
||||||
dataSet.setColor(ContextCompat.getColor(mChart.getContext(), R.color.gpx_chart_green));
|
dataSet.setColor(ContextCompat.getColor(mChart.getContext(), R.color.gpx_chart_green));
|
||||||
|
@ -1551,6 +1411,7 @@ public class GpxUiHelper {
|
||||||
dataSet.setHighLightColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
dataSet.setHighLightColor(light ? mChart.getResources().getColor(R.color.secondary_text_light) : mChart.getResources().getColor(R.color.secondary_text_dark));
|
||||||
|
|
||||||
//dataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
|
//dataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
|
||||||
|
//dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dataSet.setFillFormatter(new IFillFormatter() {
|
dataSet.setFillFormatter(new IFillFormatter() {
|
||||||
|
@ -1567,7 +1428,7 @@ public class GpxUiHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setGPXSlopeChartData(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis, boolean drawFilled) {
|
public static void setGPXSlopeChartData(OsmandApplication ctx, LineChart mChart, GPXTrackAnalysis analysis, boolean useRightAxis, boolean drawFilled) {
|
||||||
LineDataSet dataSet = createGPXSlopeDataSet(ctx, mChart, analysis, useRightAxis, drawFilled);
|
LineDataSet dataSet = createGPXSlopeDataSet(ctx, mChart, analysis, null, useRightAxis, drawFilled);
|
||||||
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
|
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
|
||||||
dataSets.add(dataSet);
|
dataSets.add(dataSet);
|
||||||
LineData data = new LineData(dataSets);
|
LineData data = new LineData(dataSets);
|
||||||
|
@ -1586,15 +1447,32 @@ public class GpxUiHelper {
|
||||||
|
|
||||||
public float priority;
|
public float priority;
|
||||||
public String units;
|
public String units;
|
||||||
|
public List<Segment> spline;
|
||||||
|
|
||||||
public OrderedLineDataSet(List<Entry> yVals, String label, GPXDataSetType dataSetType) {
|
public OrderedLineDataSet(List<Entry> yVals, String label, GPXDataSetType dataSetType) {
|
||||||
super(yVals, label);
|
super(yVals, label);
|
||||||
this.dataSetType = dataSetType;
|
this.dataSetType = dataSetType;
|
||||||
|
|
||||||
|
/*
|
||||||
|
List<Point2D> points = new ArrayList<>(yVals.size());
|
||||||
|
for (Entry e : yVals) {
|
||||||
|
points.add(new Point2D(e.getX(), e.getY()));
|
||||||
|
}
|
||||||
|
spline = calculateSpline(points);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public GPXDataSetType getDataSetType() {
|
public GPXDataSetType getDataSetType() {
|
||||||
return dataSetType;
|
return dataSetType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Segment getSegmentForEntryIndex(int index) {
|
||||||
|
if (index < spline.size()) {
|
||||||
|
return spline.get(index);
|
||||||
|
} else {
|
||||||
|
return spline.get(spline.size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
|
@ -1919,4 +1797,70 @@ public class GpxUiHelper {
|
||||||
|
|
||||||
return bezier;
|
return bezier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class SplineRenderer extends LineChartRenderer {
|
||||||
|
|
||||||
|
public SplineRenderer(LineDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
|
||||||
|
super(chart, animator, viewPortHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void drawCubicBezier(ILineDataSet dataSet) {
|
||||||
|
if (!(dataSet instanceof OrderedLineDataSet)) {
|
||||||
|
super.drawCubicBezier(dataSet);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
OrderedLineDataSet ds = (OrderedLineDataSet) dataSet;
|
||||||
|
|
||||||
|
float phaseY = mAnimator.getPhaseY();
|
||||||
|
|
||||||
|
Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
|
||||||
|
|
||||||
|
mXBounds.set(mChart, dataSet);
|
||||||
|
|
||||||
|
cubicPath.reset();
|
||||||
|
|
||||||
|
if (mXBounds.range >= 1) {
|
||||||
|
|
||||||
|
final int firstIndex = mXBounds.min + 1;
|
||||||
|
final int lastIndex = mXBounds.min + mXBounds.range;
|
||||||
|
|
||||||
|
Segment seg = ds.getSegmentForEntryIndex(Math.max(firstIndex - 1, 0));
|
||||||
|
|
||||||
|
if (seg == null) return;
|
||||||
|
|
||||||
|
// let the spline start
|
||||||
|
cubicPath.moveTo((float) seg.points[0].x, (float) seg.points[0].y * phaseY);
|
||||||
|
|
||||||
|
for (int j = firstIndex; j <= lastIndex; j++) {
|
||||||
|
|
||||||
|
seg = ds.getSegmentForEntryIndex(j);
|
||||||
|
|
||||||
|
cubicPath.cubicTo((float) seg.points[1].x, (float) seg.points[1].y * phaseY,
|
||||||
|
(float) seg.points[2].x, (float) seg.points[2].y * phaseY,
|
||||||
|
(float) seg.points[3].x, (float) seg.points[3].y * phaseY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if filled is enabled, close the path
|
||||||
|
if (ds.isDrawFilledEnabled()) {
|
||||||
|
|
||||||
|
cubicFillPath.reset();
|
||||||
|
cubicFillPath.addPath(cubicPath);
|
||||||
|
|
||||||
|
drawCubicFill(mBitmapCanvas, ds, cubicFillPath, trans, mXBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
mRenderPaint.setColor(ds.getColor());
|
||||||
|
|
||||||
|
mRenderPaint.setStyle(Paint.Style.STROKE);
|
||||||
|
|
||||||
|
trans.pathValueToPixel(cubicPath);
|
||||||
|
|
||||||
|
mBitmapCanvas.drawPath(cubicPath, mRenderPaint);
|
||||||
|
|
||||||
|
mRenderPaint.setPathEffect(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -542,6 +542,11 @@ public class TrackSegmentFragment extends OsmAndListFragment {
|
||||||
super(getActivity(), R.layout.gpx_list_item_tab_content, items);
|
super(getActivity(), R.layout.gpx_list_item_tab_content, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
super.clear();
|
super.clear();
|
||||||
|
@ -740,7 +745,8 @@ public class TrackSegmentFragment extends OsmAndListFragment {
|
||||||
case GPX_TAB_ITEM_GENERAL:
|
case GPX_TAB_ITEM_GENERAL:
|
||||||
if (analysis != null) {
|
if (analysis != null) {
|
||||||
List<ILineDataSet> dataSets = new LinkedList<>();
|
List<ILineDataSet> dataSets = new LinkedList<>();
|
||||||
if (analysis.elevationData != null || analysis.isSpeedSpecified()) {
|
if ((analysis.elevationData != null && analysis.totalDistance > 0)
|
||||||
|
|| analysis.isSpeedSpecified()) {
|
||||||
GpxUiHelper.setupGPXChart(app, chart, 4);
|
GpxUiHelper.setupGPXChart(app, chart, 4);
|
||||||
OrderedLineDataSet speedDataSet = null;
|
OrderedLineDataSet speedDataSet = null;
|
||||||
OrderedLineDataSet elevationDataSet = null;
|
OrderedLineDataSet elevationDataSet = null;
|
||||||
|
@ -810,13 +816,13 @@ public class TrackSegmentFragment extends OsmAndListFragment {
|
||||||
break;
|
break;
|
||||||
case GPX_TAB_ITEM_ALTITUDE:
|
case GPX_TAB_ITEM_ALTITUDE:
|
||||||
if (analysis != null) {
|
if (analysis != null) {
|
||||||
if (analysis.elevationData != null) {
|
if (analysis.elevationData != null && analysis.totalDistance > 0) {
|
||||||
GpxUiHelper.setupGPXChart(app, chart, 4);
|
GpxUiHelper.setupGPXChart(app, chart, 4);
|
||||||
List<ILineDataSet> dataSets = new ArrayList<>();
|
List<ILineDataSet> dataSets = new ArrayList<>();
|
||||||
OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, analysis, false, true);
|
OrderedLineDataSet elevationDataSet = GpxUiHelper.createGPXElevationDataSet(app, chart, analysis, false, true);
|
||||||
dataSets.add(elevationDataSet);
|
dataSets.add(elevationDataSet);
|
||||||
if (analysis.elevationData.size() > 1) {
|
if (analysis.elevationData.size() > 1) {
|
||||||
OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart, analysis, true, true);
|
OrderedLineDataSet slopeDataSet = GpxUiHelper.createGPXSlopeDataSet(app, chart, analysis, elevationDataSet.getValues(), true, true);
|
||||||
dataSets.add(slopeDataSet);
|
dataSets.add(slopeDataSet);
|
||||||
}
|
}
|
||||||
LineData data = new LineData(dataSets);
|
LineData data = new LineData(dataSets);
|
||||||
|
@ -861,8 +867,13 @@ public class TrackSegmentFragment extends OsmAndListFragment {
|
||||||
break;
|
break;
|
||||||
case GPX_TAB_ITEM_SPEED:
|
case GPX_TAB_ITEM_SPEED:
|
||||||
if (analysis != null && analysis.isSpeedSpecified()) {
|
if (analysis != null && analysis.isSpeedSpecified()) {
|
||||||
GpxUiHelper.setupGPXChart(app, chart, 4);
|
if (analysis.totalDistance > 0) {
|
||||||
GpxUiHelper.setGPXSpeedChartData(app, chart, analysis, false, true);
|
GpxUiHelper.setupGPXChart(app, chart, 4);
|
||||||
|
GpxUiHelper.setGPXSpeedChartData(app, chart, analysis, false, true);
|
||||||
|
chart.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
chart.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
((ImageView) view.findViewById(R.id.average_icon))
|
((ImageView) view.findViewById(R.id.average_icon))
|
||||||
.setImageDrawable(ic.getThemedIcon(R.drawable.ic_action_speed));
|
.setImageDrawable(ic.getThemedIcon(R.drawable.ic_action_speed));
|
||||||
((ImageView) view.findViewById(R.id.max_icon))
|
((ImageView) view.findViewById(R.id.max_icon))
|
||||||
|
|
Loading…
Reference in a new issue