F/filter elevations (#135)
* implement a gpx metrics computation, with filtered elevation gain and loss * Merges with main * renamed variable for clarity --------- Co-authored-by: gri38 <>
This commit is contained in:
72
web/src/lib/models/gpx/gpx-metrics-computation.ts
Normal file
72
web/src/lib/models/gpx/gpx-metrics-computation.ts
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import { haversineDistance } from './utils';
|
||||||
|
|
||||||
|
class GpxMetricsComputation {
|
||||||
|
private readonly thresholdXY_m: number; // Distance threshold for filtering on the XY axis (latitude / longitude)
|
||||||
|
private readonly thresholdZ_m: number; // Distance threshold for filtering on the Z axis (elevation)
|
||||||
|
private lastFilteredPointXY: any | null = null;
|
||||||
|
private lastFilteredZ: number | null = null;
|
||||||
|
private lastZ: number | null = null;
|
||||||
|
totalElevationGain = 0;
|
||||||
|
totalElevationLoss = 0;
|
||||||
|
totalElevationGainSmoothed = 0;
|
||||||
|
totalElevationLossSmoothed = 0;
|
||||||
|
totalDistance = 0;
|
||||||
|
totalDistanceSmoothed = 0;
|
||||||
|
|
||||||
|
constructor(thresholdXY_m: number, thresholdZ_m: number) {
|
||||||
|
this.thresholdXY_m = thresholdXY_m;
|
||||||
|
this.thresholdZ_m = thresholdZ_m;
|
||||||
|
}
|
||||||
|
|
||||||
|
addAndFilter(point: any) {
|
||||||
|
if (!this.lastFilteredPointXY) {
|
||||||
|
// Firstly, we are not yet filtering
|
||||||
|
this.lastFilteredPointXY = point;
|
||||||
|
this.lastFilteredZ = point.ele ?? 0;
|
||||||
|
this.lastZ = point.ele ?? 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const distance = haversineDistance(
|
||||||
|
this.lastFilteredPointXY.$.lat,
|
||||||
|
this.lastFilteredPointXY.$.lon,
|
||||||
|
point.$.lat,
|
||||||
|
point.$.lon
|
||||||
|
);
|
||||||
|
|
||||||
|
this.totalDistance += distance;
|
||||||
|
const elevation = point.ele ?? 0;
|
||||||
|
// @ts-ignore I know this.lastZ is not null
|
||||||
|
const elevationDiff = elevation - this.lastZ;
|
||||||
|
this.lastZ = elevation;
|
||||||
|
if (elevationDiff > 0) {
|
||||||
|
this.totalElevationGain += elevationDiff;
|
||||||
|
}
|
||||||
|
if (elevationDiff < 0) {
|
||||||
|
this.totalElevationLoss -= elevationDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distance < this.thresholdXY_m) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.totalDistanceSmoothed += distance;
|
||||||
|
|
||||||
|
this.lastFilteredPointXY = point;
|
||||||
|
// @ts-ignore: I know this.lastFilteredZ is not null
|
||||||
|
const elevationDiffSmoothed = elevation - this.lastFilteredZ;
|
||||||
|
|
||||||
|
if (Math.abs(elevationDiffSmoothed) < this.thresholdZ_m) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastFilteredZ = elevation;
|
||||||
|
if (elevationDiffSmoothed > 0) {
|
||||||
|
this.totalElevationGainSmoothed += elevationDiffSmoothed;
|
||||||
|
} else {
|
||||||
|
this.totalElevationLossSmoothed -= elevationDiffSmoothed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GpxMetricsComputation;
|
||||||
@@ -4,6 +4,7 @@ import Route from './route';
|
|||||||
import Track from './track';
|
import Track from './track';
|
||||||
import { allDatesToISOString, haversineDistance, removeEmpty } from './utils';
|
import { allDatesToISOString, haversineDistance, removeEmpty } from './utils';
|
||||||
import Waypoint from './waypoint';
|
import Waypoint from './waypoint';
|
||||||
|
import GpxMetricsComputation from './gpx-metrics-computation';
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
import geohash from "ngeohash"
|
import geohash from "ngeohash"
|
||||||
|
|
||||||
@@ -96,6 +97,8 @@ export default class GPX {
|
|||||||
let totalLat = 0
|
let totalLat = 0
|
||||||
let totalLon = 0
|
let totalLon = 0
|
||||||
|
|
||||||
|
const metrics = new GpxMetricsComputation(5, 10);
|
||||||
|
|
||||||
let minLat = Infinity, maxLat = -Infinity, minLon = Infinity, maxLon = -Infinity;
|
let minLat = Infinity, maxLat = -Infinity, minLon = Infinity, maxLon = -Infinity;
|
||||||
|
|
||||||
const allPoints: Waypoint[] = []
|
const allPoints: Waypoint[] = []
|
||||||
@@ -115,23 +118,8 @@ export default class GPX {
|
|||||||
|
|
||||||
const pointLength = points.length
|
const pointLength = points.length
|
||||||
for (let i = 1; i < pointLength; i++) {
|
for (let i = 1; i < pointLength; i++) {
|
||||||
const prevPoint = points[i - 1];
|
|
||||||
const point = points[i];
|
const point = points[i];
|
||||||
const elevation = point.ele ?? 0
|
metrics.addAndFilter(point)
|
||||||
const previousElevation = prevPoint.ele ?? 0
|
|
||||||
const elevationDiff = elevation - previousElevation;
|
|
||||||
if (elevationDiff > 0) {
|
|
||||||
totalElevationGain += elevationDiff;
|
|
||||||
} else {
|
|
||||||
totalElevationLoss += Math.abs(elevationDiff)
|
|
||||||
}
|
|
||||||
|
|
||||||
const distance = haversineDistance(
|
|
||||||
prevPoint.$.lat ?? 0,
|
|
||||||
prevPoint.$.lon ?? 0,
|
|
||||||
point.$.lat ?? 0,
|
|
||||||
point.$.lon ?? 0,
|
|
||||||
);
|
|
||||||
|
|
||||||
totalLat += point.$.lat ?? 0;
|
totalLat += point.$.lat ?? 0;
|
||||||
totalLon += point.$.lon ?? 0;
|
totalLon += point.$.lon ?? 0;
|
||||||
@@ -140,11 +128,14 @@ export default class GPX {
|
|||||||
maxLat = Math.max(maxLat, point.$.lat ?? -Infinity);
|
maxLat = Math.max(maxLat, point.$.lat ?? -Infinity);
|
||||||
minLon = Math.min(minLon, point.$.lon ?? Infinity);
|
minLon = Math.min(minLon, point.$.lon ?? Infinity);
|
||||||
maxLon = Math.max(maxLon, point.$.lon ?? -Infinity);
|
maxLon = Math.max(maxLon, point.$.lon ?? -Infinity);
|
||||||
totalDistance += distance;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalElevationGain = metrics.totalElevationGainSmoothed;
|
||||||
|
totalElevationLoss = metrics.totalElevationLossSmoothed;
|
||||||
|
totalDistance = metrics.totalDistance;
|
||||||
|
|
||||||
const boundingBox = { minLat, maxLat, minLon, maxLon };
|
const boundingBox = { minLat, maxLat, minLon, maxLon };
|
||||||
const centroid = { lat: totalLat / allPoints.length, lon: totalLon / allPoints.length };
|
const centroid = { lat: totalLat / allPoints.length, lon: totalLon / allPoints.length };
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user