Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix recalculating statistics when changing parameters #21767

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package net.osmand.shared.gpx

import co.touchlab.stately.concurrency.AtomicLong
import kotlin.collections.MutableMap
import kotlin.collections.HashMap
import net.osmand.shared.gpx.GpxParameter.*
import net.osmand.shared.io.KFile

abstract class DataItem(val file: KFile) {
protected val map: MutableMap<GpxParameter, Any?> = HashMap()
private var analysisParametersVersion = AtomicLong(0)

init {
initFileParameters()
Expand Down Expand Up @@ -54,6 +56,12 @@ abstract class DataItem(val file: KFile) {
}
}

fun getAnalysisCalculationParameters() = map.filter { it.key.analysisCalculation }

fun getAnalysisParametersVersion() = analysisParametersVersion.get()

fun increaseAnalysisParametersVersion() = analysisParametersVersion.incrementAndGet()

open fun isValidValue(parameter: GpxParameter, value: Any?): Boolean {
return true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ object GpxDbHelper : GpxReaderAdapter {
): Boolean {
item.setParameter(parameter, value)
val res = database.updateDataItemParameter(item, parameter, value)
if (res && parameter.analysisCalculation) {
// Reset DATA_VERSION to force recalculation of analysis
item.setParameter(GpxParameter.DATA_VERSION, 0)
item.increaseAnalysisParametersVersion()
database.updateDataItemParameter(item, GpxParameter.DATA_VERSION, 0)
}
putToCache(item)
return res
}
Expand Down Expand Up @@ -234,6 +240,10 @@ object GpxDbHelper : GpxReaderAdapter {
return getItem(file, null)
}

fun getItem(file: KFile, readIfNeeded: Boolean): GpxDataItem? {
return getItem(file, null, readIfNeeded)
}

fun getGpxDirItem(file: KFile): GpxDirItem {
var item = dirItems[file]
if (item == null) {
Expand All @@ -247,11 +257,15 @@ object GpxDbHelper : GpxReaderAdapter {
}

fun getItem(file: KFile, callback: GpxDataItemCallback?): GpxDataItem? {
return getItem(file, callback, true)
}

fun getItem(file: KFile, callback: GpxDataItemCallback?, readIfNeeded: Boolean): GpxDataItem? {
if (file.isPathEmpty()) {
return null
}
val item = dataItems[file]
if (GpxDbUtils.isAnalyseNeeded(item) && GpxDataItem.isRegularTrack(file)) {
if (readIfNeeded && GpxDbUtils.isAnalyseNeeded(item) && GpxDataItem.isRegularTrack(file)) {
readGpxItem(file, item, callback)
}
return item
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import net.osmand.shared.gpx.primitives.Route
import net.osmand.shared.gpx.primitives.Track
import net.osmand.shared.gpx.primitives.TrkSegment
import net.osmand.shared.gpx.primitives.WptPt
import net.osmand.shared.io.KFile
import net.osmand.shared.util.KMapUtils
import kotlin.collections.set

Expand Down Expand Up @@ -262,19 +263,40 @@ class GpxFile : GpxExtensions {
}

fun getAnalysis(fileTimestamp: Long): GpxTrackAnalysis {
return getAnalysis(fileTimestamp, null, null, null)
val parameters = if (path.isNotEmpty())
GpxDbHelper.getItem(KFile(path), false)?.getAnalysisCalculationParameters() else null
return getAnalysis(fileTimestamp, null, null, parameters, null)
}

fun getAnalysis(fileTimestamp: Long, parameters: Map<GpxParameter, Any?>?): GpxTrackAnalysis {
return getAnalysis(fileTimestamp, null, null, parameters, null)
}

fun getAnalysis(
fileTimestamp: Long,
fromDistance: Double?,
toDistance: Double?,
pointsAnalyzer: GpxTrackAnalysis.TrackPointsAnalyser?
): GpxTrackAnalysis {
val parameters = if (path.isNotEmpty())
GpxDbHelper.getItem(KFile(path), false)?.getAnalysisCalculationParameters() else null
return getAnalysis(fileTimestamp, fromDistance, toDistance, parameters, pointsAnalyzer)
}

fun getAnalysis(
fileTimestamp: Long,
fromDistance: Double?,
toDistance: Double?,
parameters: Map<GpxParameter, Any?>?,
pointsAnalyzer: GpxTrackAnalysis.TrackPointsAnalyser?
): GpxTrackAnalysis {
val analysis = GpxTrackAnalysis()
analysis.name = path
analysis.wptPoints = points.size
analysis.setWptCategoryNames(getWaypointCategories())
if (parameters != null) {
analysis.setGpxParameters(parameters)
}

val segments = getSplitSegments(analysis, fromDistance, toDistance)
analysis.prepareInformation(fileTimestamp, pointsAnalyzer, *segments.toTypedArray())
Expand All @@ -287,6 +309,12 @@ class GpxFile : GpxExtensions {
toDistance: Double?
): List<SplitSegment> {
val splitSegments = mutableListOf<SplitSegment>()
if (fromDistance == null || toDistance == null) {
getGeneralSegment()?.let {
splitSegments.add(SplitSegment(it))
return splitSegments
}
}
for (subtrack in tracks) {
for (segment in subtrack.segments) {
if (!segment.generalSegment) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,69 +8,70 @@ enum class GpxParameter(
val columnType: String,
val typeClass: KClass<*>,
val defaultValue: Any?,
val analysisParameter: Boolean
val analysisParameter: Boolean,
val analysisCalculation: Boolean
) {
FILE_NAME("fileName", "TEXT", String::class, null, false),
FILE_DIR("fileDir", "TEXT", String::class, null, false),
TOTAL_DISTANCE("totalDistance", "double", Double::class, 0.0, true),
TOTAL_TRACKS("totalTracks", "int", Int::class, 0, true),
START_TIME("startTime", "bigint", Long::class, Long.MAX_VALUE, true),
END_TIME("endTime", "bigint", Long::class, Long.MIN_VALUE, true),
TIME_SPAN("timeSpan", "bigint", Long::class, 0L, true),
EXPECTED_DURATION("expectedDuration", "bigint", Long::class, 0L, true),
TIME_MOVING("timeMoving", "bigint", Long::class, 0L, true),
TOTAL_DISTANCE_MOVING("totalDistanceMoving", "double", Double::class, 0.0, true),
DIFF_ELEVATION_UP("diffElevationUp", "double", Double::class, 0.0, true),
DIFF_ELEVATION_DOWN("diffElevationDown", "double", Double::class, 0.0, true),
AVG_ELEVATION("avgElevation", "double", Double::class, 0.0, true),
MIN_ELEVATION("minElevation", "double", Double::class, 99999.0, true),
MAX_ELEVATION("maxElevation", "double", Double::class, -100.0, true),
MIN_SPEED("minSpeed", "double", Double::class, Float.MAX_VALUE.toDouble(), true),
MAX_SPEED("maxSpeed", "double", Double::class, 0.0, true),
AVG_SPEED("avgSpeed", "double", Double::class, 0.0, true),
POINTS("points", "int", Int::class, 0, true),
WPT_POINTS("wptPoints", "int", Int::class, 0, true),
COLOR("color", "TEXT", Int::class, null, false),
FILE_LAST_MODIFIED_TIME("fileLastModifiedTime", "bigint", Long::class, 0L, false),
FILE_LAST_UPLOADED_TIME("fileLastUploadedTime", "bigint", Long::class, 0L, false),
FILE_CREATION_TIME("fileCreationTime", "bigint", Long::class, -1L, false),
SPLIT_TYPE("splitType", "int", Int::class, 0, false),
SPLIT_INTERVAL("splitInterval", "double", Double::class, 0.0, false),
API_IMPORTED("apiImported", "int", Boolean::class, false, false),
WPT_CATEGORY_NAMES("wptCategoryNames", "TEXT", String::class, null, true),
SHOW_AS_MARKERS("showAsMarkers", "int", Boolean::class, false, false),
JOIN_SEGMENTS("joinSegments", "int", Boolean::class, false, false),
SHOW_ARROWS("showArrows", "int", Boolean::class, false, false),
SHOW_START_FINISH("showStartFinish", "int", Boolean::class, true, false),
TRACK_VISUALIZATION_TYPE("track_visualization_type", "TEXT", String::class, "none", false),
TRACK_3D_WALL_COLORING_TYPE("track_3d_wall_coloring_type", "TEXT", String::class, "none", false),
TRACK_3D_LINE_POSITION_TYPE("track_3d_line_position_type", "TEXT", String::class, "top", false),
ADDITIONAL_EXAGGERATION("additional_exaggeration", "double", Double::class, 1.0, false),
ELEVATION_METERS("elevation_meters", "double", Double::class, 1000.0, false),
WIDTH("width", "TEXT", String::class, null, false),
COLORING_TYPE("gradientScaleType", "TEXT", String::class, null, false),
COLOR_PALETTE("colorPalette", "TEXT", String::class, null, false),
SMOOTHING_THRESHOLD("smoothingThreshold", "double", Double::class, Double.NaN, false),
MIN_FILTER_SPEED("minFilterSpeed", "double", Double::class, Double.NaN, false),
MAX_FILTER_SPEED("maxFilterSpeed", "double", Double::class, Double.NaN, false),
MIN_FILTER_ALTITUDE("minFilterAltitude", "double", Double::class, Double.NaN, false),
MAX_FILTER_ALTITUDE("maxFilterAltitude", "double", Double::class, Double.NaN, false),
MAX_FILTER_HDOP("maxFilterHdop", "double", Double::class, Double.NaN, false),
START_LAT("startLat", "double", Double::class, null, true),
START_LON("startLon", "double", Double::class, null, true),
NEAREST_CITY_NAME("nearestCityName", "TEXT", String::class, null, false),
ACTIVITY_TYPE("activityType", "TEXT", String::class, null, false),
MAX_SENSOR_TEMPERATURE("maxSensorTemperature", "int", Int::class, 0, true),
AVG_SENSOR_TEMPERATURE("avgSensorTemperature", "double", Double::class, 0.0, true),
MAX_SENSOR_SPEED("maxSensorSpeed", "double", Double::class, 0.0, true),
AVG_SENSOR_SPEED("avgSensorSpeed", "double", Double::class, 0.0, true),
MAX_SENSOR_POWER("maxSensorPower", "int", Int::class, 0, true),
AVG_SENSOR_POWER("avgSensorPower", "double", Double::class, 0.0, true),
MAX_SENSOR_CADENCE("maxSensorCadence", "double", Double::class, 0.0, true),
AVG_SENSOR_CADENCE("avgSensorCadence", "double", Double::class, 0.0, true),
MAX_SENSOR_HEART_RATE("maxSensorHr", "int", Int::class, 0, true),
AVG_SENSOR_HEART_RATE("avgSensorHr", "double", Double::class, 0.0, true),
DATA_VERSION("dataVersion", "int", Int::class, 0, false);
FILE_NAME("fileName", "TEXT", String::class, null, false, false),
FILE_DIR("fileDir", "TEXT", String::class, null, false, false),
TOTAL_DISTANCE("totalDistance", "double", Double::class, 0.0, true, false),
TOTAL_TRACKS("totalTracks", "int", Int::class, 0, true, false),
START_TIME("startTime", "bigint", Long::class, Long.MAX_VALUE, true, false),
END_TIME("endTime", "bigint", Long::class, Long.MIN_VALUE, true, false),
TIME_SPAN("timeSpan", "bigint", Long::class, 0L, true, false),
EXPECTED_DURATION("expectedDuration", "bigint", Long::class, 0L, true, false),
TIME_MOVING("timeMoving", "bigint", Long::class, 0L, true, false),
TOTAL_DISTANCE_MOVING("totalDistanceMoving", "double", Double::class, 0.0, true, false),
DIFF_ELEVATION_UP("diffElevationUp", "double", Double::class, 0.0, true, false),
DIFF_ELEVATION_DOWN("diffElevationDown", "double", Double::class, 0.0, true, false),
AVG_ELEVATION("avgElevation", "double", Double::class, 0.0, true, false),
MIN_ELEVATION("minElevation", "double", Double::class, 99999.0, true, false),
MAX_ELEVATION("maxElevation", "double", Double::class, -100.0, true, false),
MIN_SPEED("minSpeed", "double", Double::class, Float.MAX_VALUE.toDouble(), true, false),
MAX_SPEED("maxSpeed", "double", Double::class, 0.0, true, false),
AVG_SPEED("avgSpeed", "double", Double::class, 0.0, true, false),
POINTS("points", "int", Int::class, 0, true, false),
WPT_POINTS("wptPoints", "int", Int::class, 0, true, false),
COLOR("color", "TEXT", Int::class, null, false, false),
FILE_LAST_MODIFIED_TIME("fileLastModifiedTime", "bigint", Long::class, 0L, false, false),
FILE_LAST_UPLOADED_TIME("fileLastUploadedTime", "bigint", Long::class, 0L, false, false),
FILE_CREATION_TIME("fileCreationTime", "bigint", Long::class, -1L, false, false),
SPLIT_TYPE("splitType", "int", Int::class, 0, false, false),
SPLIT_INTERVAL("splitInterval", "double", Double::class, 0.0, false, false),
API_IMPORTED("apiImported", "int", Boolean::class, false, false, false),
WPT_CATEGORY_NAMES("wptCategoryNames", "TEXT", String::class, null, true, false),
SHOW_AS_MARKERS("showAsMarkers", "int", Boolean::class, false, false, false),
JOIN_SEGMENTS("joinSegments", "int", Boolean::class, false, false, true),
SHOW_ARROWS("showArrows", "int", Boolean::class, false, false, false),
SHOW_START_FINISH("showStartFinish", "int", Boolean::class, true, false, false),
TRACK_VISUALIZATION_TYPE("track_visualization_type", "TEXT", String::class, "none", false, false),
TRACK_3D_WALL_COLORING_TYPE("track_3d_wall_coloring_type", "TEXT", String::class, "none", false, false),
TRACK_3D_LINE_POSITION_TYPE("track_3d_line_position_type", "TEXT", String::class, "top", false, false),
ADDITIONAL_EXAGGERATION("additional_exaggeration", "double", Double::class, 1.0, false, false),
ELEVATION_METERS("elevation_meters", "double", Double::class, 1000.0, false, false),
WIDTH("width", "TEXT", String::class, null, false, false),
COLORING_TYPE("gradientScaleType", "TEXT", String::class, null, false, false),
COLOR_PALETTE("colorPalette", "TEXT", String::class, null, false, false),
SMOOTHING_THRESHOLD("smoothingThreshold", "double", Double::class, Double.NaN, false, false),
MIN_FILTER_SPEED("minFilterSpeed", "double", Double::class, Double.NaN, false, false),
MAX_FILTER_SPEED("maxFilterSpeed", "double", Double::class, Double.NaN, false, false),
MIN_FILTER_ALTITUDE("minFilterAltitude", "double", Double::class, Double.NaN, false, false),
MAX_FILTER_ALTITUDE("maxFilterAltitude", "double", Double::class, Double.NaN, false, false),
MAX_FILTER_HDOP("maxFilterHdop", "double", Double::class, Double.NaN, false, false),
START_LAT("startLat", "double", Double::class, null, true, false),
START_LON("startLon", "double", Double::class, null, true, false),
NEAREST_CITY_NAME("nearestCityName", "TEXT", String::class, null, false, false),
ACTIVITY_TYPE("activityType", "TEXT", String::class, null, false, false),
MAX_SENSOR_TEMPERATURE("maxSensorTemperature", "int", Int::class, 0, true, false),
AVG_SENSOR_TEMPERATURE("avgSensorTemperature", "double", Double::class, 0.0, true, false),
MAX_SENSOR_SPEED("maxSensorSpeed", "double", Double::class, 0.0, true, false),
AVG_SENSOR_SPEED("avgSensorSpeed", "double", Double::class, 0.0, true, false),
MAX_SENSOR_POWER("maxSensorPower", "int", Int::class, 0, true, false),
AVG_SENSOR_POWER("avgSensorPower", "double", Double::class, 0.0, true, false),
MAX_SENSOR_CADENCE("maxSensorCadence", "double", Double::class, 0.0, true, false),
AVG_SENSOR_CADENCE("avgSensorCadence", "double", Double::class, 0.0, true, false),
MAX_SENSOR_HEART_RATE("maxSensorHr", "int", Int::class, 0, true, false),
AVG_SENSOR_HEART_RATE("avgSensorHr", "double", Double::class, 0.0, true, false),
DATA_VERSION("dataVersion", "int", Int::class, 0, false, false);

fun isNullSupported(): Boolean = defaultValue == null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ class GpxTrackAnalysis {
companion object {
const val ANALYSIS_VERSION = 1

fun prepareInformation(
fileTimeStamp: Long, pointsAnalyzer: TrackPointsAnalyser, segment: TrkSegment
): GpxTrackAnalysis {
return GpxTrackAnalysis().prepareInformation(
fileTimeStamp, pointsAnalyzer, SplitSegment(segment)
)
fun prepareInformation(fileTimeStamp: Long,
joinSegments: Boolean,
pointsAnalyzer: TrackPointsAnalyser,
segment: TrkSegment): GpxTrackAnalysis {
val analysis = GpxTrackAnalysis()
analysis.joinSegments = joinSegments
return analysis.prepareInformation(fileTimeStamp, pointsAnalyzer, SplitSegment(segment))
}
}

Expand Down Expand Up @@ -60,6 +61,10 @@ class GpxTrackAnalysis {
parameters[parameter] = value
}

fun setGpxParameters(parameters: Map<GpxParameter, Any?>) {
this.parameters.putAll(parameters)
}

var startTime: Long
get() = getGpxParameter(GpxParameter.START_TIME) as Long
set(value) = setGpxParameter(GpxParameter.START_TIME, value)
Expand Down Expand Up @@ -455,7 +460,7 @@ class GpxTrackAnalysis {
}


if (joinSegments && totalDistanceWithoutGaps > 0) {
if (!joinSegments && totalDistanceWithoutGaps > 0) {
totalDistance = totalDistanceWithoutGaps
} else {
totalDistance = _totalDistance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ public class SplitSegmentDialogFragment extends BaseOsmAndDialogFragment {
private SplitSegmentsAdapter adapter;

private int selectedSplitInterval;
private final boolean joinSegments = false;

@Override
public void onCreate(Bundle savedInstanceState) {
Expand Down Expand Up @@ -102,7 +101,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
listView.setDivider(null);
listView.setDividerHeight(0);

adapter = new SplitSegmentsAdapter(requireActivity(), new ArrayList<>(), displayItem, joinSegments);
adapter = new SplitSegmentsAdapter(requireActivity(), new ArrayList<>(), displayItem);
headerView = view.findViewById(R.id.header_layout);

ImageView splitImage = headerView.findViewById(R.id.header_split_image);
Expand Down Expand Up @@ -224,7 +223,7 @@ private void updateSplit(@NonNull List<GpxDisplayGroup> groups, @NonNull Selecte
splitInterval = timeSplit.get(selectedSplitInterval);
}
SplitTrackListener listener = getSplitTrackListener(selectedGpxFile);
GpxSplitParams params = new GpxSplitParams(splitType, splitInterval, joinSegments);
GpxSplitParams params = new GpxSplitParams(splitType, splitInterval, false);

app.getGpxDisplayHelper().splitTrackAsync(selectedGpxFile, groups, params, listener);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,18 @@ class SplitSegmentsAdapter extends ArrayAdapter<GpxDisplayItem> {

private final Rect minMaxSpeedTextBounds = new Rect();
private final GpxDisplayItem displayItem;
private final boolean joinSegments;
private int minMaxSpeedLayoutWidth;

private final Paint minMaxSpeedPaint = new Paint();
private ColorStateList defaultTextColor;

SplitSegmentsAdapter(@NonNull FragmentActivity activity,
@NonNull List<GpxDisplayItem> items,
@NonNull GpxDisplayItem displayItem,
boolean joinSegments) {
@NonNull GpxDisplayItem displayItem) {
super(activity, 0, items);
this.activity = activity;
this.app = (OsmandApplication) activity.getApplicationContext();
this.displayItem = displayItem;
this.joinSegments = joinSegments;

minMaxSpeedPaint.setTextSize(app.getResources().getDimension(R.dimen.default_split_segments_data));
minMaxSpeedPaint.setTypeface(FontCache.getMediumFont());
Expand Down Expand Up @@ -146,7 +143,7 @@ public View getView(int position, @Nullable View convertView, @NonNull ViewGroup
TextView distanceOrTimeSpanText = convertView.findViewById(R.id.distance_or_time_span_text);
if (position == 0) {
distanceOrTimeSpanImageView.setImageDrawable(getIcon(R.drawable.ic_action_track_16, app.getSettings().isLightContent() ? R.color.gpx_split_segment_icon_color : 0));
float totalDistance = !joinSegments && displayItem.isGeneralTrack() ? analysis.getTotalDistanceWithoutGaps() : analysis.getTotalDistance();
float totalDistance = displayItem.isGeneralTrack() ? analysis.getTotalDistanceWithoutGaps() : analysis.getTotalDistance();
distanceOrTimeSpanValue.setText(OsmAndFormatter.getFormattedDistance(totalDistance, app));
distanceOrTimeSpanText.setText(app.getString(R.string.distance));
} else {
Expand Down
4 changes: 3 additions & 1 deletion OsmAnd/src/net/osmand/plus/track/SplitTrackAsyncTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,9 @@ private static GpxTrackAnalysis[] getTrackAnalysis(@NonNull TrkSegment segment,
List<GpxTrackAnalysis> trackAnalyses = segment.splitByTime(splitTime, joinSegments);
return trackAnalyses.toArray(new GpxTrackAnalysis[0]);
} else {
return new GpxTrackAnalysis[] {GpxTrackAnalysis.Companion.prepareInformation(0, pointsAnalyser, segment)};
return new GpxTrackAnalysis[] {
GpxTrackAnalysis.Companion.prepareInformation(0, joinSegments, pointsAnalyser, segment)
};
}
}

Expand Down
Loading
Loading