From ff3ef4121ebc8e9c2822418068ce1859c62b76c1 Mon Sep 17 00:00:00 2001 From: Wolfgang Klenk Date: Sun, 29 Dec 2024 23:04:58 +0100 Subject: [PATCH] Optimize algorithm to calculate grade. --- src/app/services/grade-processor.service.ts | 46 +++++++++++++++------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/app/services/grade-processor.service.ts b/src/app/services/grade-processor.service.ts index 6f1b549..6daf1c6 100644 --- a/src/app/services/grade-processor.service.ts +++ b/src/app/services/grade-processor.service.ts @@ -31,25 +31,47 @@ export class GradeProcessorService implements DataProcessor { } private findGradeByDistance(distance: number): number { - if (!this.reducedWaypoints) { - return 0 + throw Error() + } + + const closestWaypointIndex = this.findWaypointIndexClosestToDistance(distance) + if (closestWaypointIndex === 0 || closestWaypointIndex === this.reducedWaypoints.length - 1) { + return 0; // Start or end of track } - for (let i = 0; i < this.reducedWaypoints.length - 1; i++) { - const elevationData0 = this.reducedWaypoints[i] - const elevationData1 = this.reducedWaypoints[i + 1] + const elevationData0 = this.reducedWaypoints[closestWaypointIndex - 1] + const elevationData1 = this.reducedWaypoints[closestWaypointIndex + 1] + + const distanceDiff = elevationData1.distance - elevationData0.distance + const elevationDiff = elevationData1.elevation - elevationData0.elevation + + const horizontalDiff = Math.sqrt(distanceDiff ** 2 - elevationDiff ** 2) + + return elevationDiff / horizontalDiff * 100 // in % + } + + private findWaypointIndexClosestToDistance(distance: number): number { + if (!this.reducedWaypoints) { + throw Error() + } - if (distance >= elevationData0.distance && distance < elevationData1.distance) { - const distanceDiff = elevationData1.distance - elevationData0.distance - const elevationDiff = elevationData1.elevation - elevationData0.elevation + let left = 0; + let right = this.reducedWaypoints.length - 1; - const horizontalDiff = Math.sqrt(distanceDiff ** 2 - elevationDiff ** 2) + while (left <= right) { + const mid = Math.floor((left + right) / 2) + const midDistance = this.reducedWaypoints[mid].distance - return elevationDiff / horizontalDiff * 100 // in % + if (midDistance === distance) { + return mid + } else if (midDistance < distance) { + left = mid + 1 + } else { + right = mid - 1 } } - return 0 + return left < this.reducedWaypoints.length ? left : this.reducedWaypoints.length - 1 } -} \ No newline at end of file +}