Break out of infinite loops when calculating required speed, add waypoints to gpx that show when you have to start accelerating
This commit is contained in:
parent
06fa1be52b
commit
7c0dd3ee4e
@ -473,6 +473,11 @@ float calculateRequiredSpeed(float endSpeed, float horizontalDistance, float hei
|
|||||||
float numerator = 0;
|
float numerator = 0;
|
||||||
float denominator = 0.5;
|
float denominator = 0.5;
|
||||||
float foundEndSpeed = -100.0;
|
float foundEndSpeed = -100.0;
|
||||||
|
int loopCounter = 0;
|
||||||
|
|
||||||
|
float closestFoundSpeed = 1e99;
|
||||||
|
float bestNumerator = 1;
|
||||||
|
float bestDenominator = 1;
|
||||||
do {
|
do {
|
||||||
numerator *= 2;
|
numerator *= 2;
|
||||||
denominator *= 2;
|
denominator *= 2;
|
||||||
@ -482,9 +487,16 @@ float calculateRequiredSpeed(float endSpeed, float horizontalDistance, float hei
|
|||||||
numerator += 1;
|
numerator += 1;
|
||||||
}
|
}
|
||||||
foundEndSpeed = calculate_speed(maximumSpeed * numerator / denominator, horizontalDistance, heightDifference, 0.01, 100.0, dragCoefficient);
|
foundEndSpeed = calculate_speed(maximumSpeed * numerator / denominator, horizontalDistance, heightDifference, 0.01, 100.0, dragCoefficient);
|
||||||
} while (fabs(foundEndSpeed - endSpeed) > 0.013);
|
loopCounter++;
|
||||||
|
|
||||||
float requiredSpeed = maximumSpeed * numerator / denominator;
|
if (fabs(foundEndSpeed - endSpeed) < closestFoundSpeed) {
|
||||||
|
closestFoundSpeed = foundEndSpeed;
|
||||||
|
bestNumerator = numerator;
|
||||||
|
bestDenominator = denominator;
|
||||||
|
}
|
||||||
|
} while (fabs(foundEndSpeed - endSpeed) > 0.013 && loopCounter < 32);
|
||||||
|
|
||||||
|
float requiredSpeed = maximumSpeed * bestNumerator / bestDenominator;
|
||||||
|
|
||||||
return requiredSpeed;
|
return requiredSpeed;
|
||||||
}
|
}
|
||||||
@ -546,7 +558,7 @@ std::vector<JSNodeInfo> getPathJS(uint32_t startingNode, uint32_t endNode, float
|
|||||||
Connection neighbour = neighbours[i];
|
Connection neighbour = neighbours[i];
|
||||||
if (neighbour.connected_point_number == nextNodeId) {
|
if (neighbour.connected_point_number == nextNodeId) {
|
||||||
float horizontalDistance = neighbour.distance;
|
float horizontalDistance = neighbour.distance;
|
||||||
currentRequiredSpeed = calculateRequiredSpeed(currentRequiredSpeed, horizontalDistance, heightDifference, dragCoefficient);
|
currentRequiredSpeed = fmax(calculateRequiredSpeed(currentRequiredSpeed, horizontalDistance, heightDifference, dragCoefficient), minimumSpeed);
|
||||||
it->requiredSpeed = currentRequiredSpeed;
|
it->requiredSpeed = currentRequiredSpeed;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
import type { Coordinate, PathSegment } from "../../interfaces";
|
import type { Coordinate, PathSegment } from "../../interfaces";
|
||||||
|
|
||||||
|
interface HighspeedSegment {
|
||||||
|
startingSegmentNumber: number,
|
||||||
|
segmentLength: number,
|
||||||
|
highestSpeed: number,
|
||||||
|
highestSpeedSegmentNumber: number
|
||||||
|
}
|
||||||
|
|
||||||
function createAndAppendChild(document: XMLDocument, parent: HTMLElement, nameOfChild: string, contents?: string): HTMLElement {
|
function createAndAppendChild(document: XMLDocument, parent: HTMLElement, nameOfChild: string, contents?: string): HTMLElement {
|
||||||
let childElement = document.createElement(nameOfChild);
|
let childElement = document.createElement(nameOfChild);
|
||||||
parent.appendChild(childElement);
|
parent.appendChild(childElement);
|
||||||
@ -16,8 +23,22 @@ function createRoutePoint(document: XMLDocument, parent: HTMLElement, coordinate
|
|||||||
createAndAppendChild(document, routePoint, 'desc', 'Required speed: ' + (requiredSpeed * 3.6).toFixed(1) + ' km/h');
|
createAndAppendChild(document, routePoint, 'desc', 'Required speed: ' + (requiredSpeed * 3.6).toFixed(1) + ' km/h');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createWaypoint(document: XMLDocument, parent: HTMLElement, name: string, coordinate: Coordinate, color: string): void {
|
||||||
|
let waypoint = createAndAppendChild(document, parent, 'wpt');
|
||||||
|
waypoint.setAttribute('lat', coordinate.latitude.toFixed(6));
|
||||||
|
waypoint.setAttribute('lon', coordinate.longitude.toFixed(6));
|
||||||
|
createAndAppendChild(document, waypoint, 'name', name);
|
||||||
|
let extensions = createAndAppendChild(document, waypoint, 'extensions');
|
||||||
|
let colorTag = document.createElementNS('https://osmand.net/docs/technical/osmand-file-formats/osmand-gpx', 'color');
|
||||||
|
extensions.appendChild(colorTag);
|
||||||
|
colorTag.appendChild(document.createTextNode(color));
|
||||||
|
}
|
||||||
|
|
||||||
export function downloadGpxFile(path: PathSegment[]): void {
|
export function downloadGpxFile(path: PathSegment[]): void {
|
||||||
let gpxDocument = document.implementation.createDocument('http://www.topografix.com/GPX/1/1', 'gpx');
|
let gpxDocument = document.implementation.createDocument('http://www.topografix.com/GPX/1/1', 'gpx');
|
||||||
|
gpxDocument.documentElement.setAttribute('version', '1.1');
|
||||||
|
gpxDocument.documentElement.setAttribute('creator', 'https://freewheeling.martinserver.no');
|
||||||
|
|
||||||
|
|
||||||
let routeElement = createAndAppendChild(gpxDocument, gpxDocument.documentElement, 'rte');
|
let routeElement = createAndAppendChild(gpxDocument, gpxDocument.documentElement, 'rte');
|
||||||
createAndAppendChild(gpxDocument, routeElement, 'name', 'Freewheeling route');
|
createAndAppendChild(gpxDocument, routeElement, 'name', 'Freewheeling route');
|
||||||
@ -28,10 +49,69 @@ export function downloadGpxFile(path: PathSegment[]): void {
|
|||||||
if (path.length > 0) {
|
if (path.length > 0) {
|
||||||
createRoutePoint(gpxDocument, routeElement, path.at(0)!.start, path.at(0)!.requiredSpeed);
|
createRoutePoint(gpxDocument, routeElement, path.at(0)!.start, path.at(0)!.requiredSpeed);
|
||||||
}
|
}
|
||||||
|
// Add remaining route points
|
||||||
path.forEach(segment => {
|
path.forEach(segment => {
|
||||||
createRoutePoint(gpxDocument, routeElement, segment.end, segment.requiredSpeed);
|
createRoutePoint(gpxDocument, routeElement, segment.end, segment.requiredSpeed);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add waypoints where you need to start accelerating, where you reach top speed, and where you can start rolling normally again
|
||||||
|
var minimumSpeed: number = Math.min(...path.map(segment => segment.requiredSpeed));
|
||||||
|
var highspeedSegments: HighspeedSegment[] = [];
|
||||||
|
var currentSegment: HighspeedSegment | undefined = undefined;
|
||||||
|
|
||||||
|
for (var i = 0; i < path.length; i++) {
|
||||||
|
var segment = path[i];
|
||||||
|
if (segment.requiredSpeed - minimumSpeed > 0.01) {
|
||||||
|
if (currentSegment == null) {
|
||||||
|
currentSegment = {
|
||||||
|
startingSegmentNumber: i,
|
||||||
|
segmentLength: 1,
|
||||||
|
highestSpeed: -1,
|
||||||
|
highestSpeedSegmentNumber: -1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentSegment.segmentLength += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (currentSegment != null) {
|
||||||
|
highspeedSegments.push(currentSegment);
|
||||||
|
currentSegment = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSegment != null) {
|
||||||
|
highspeedSegments.push(currentSegment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the highest speed inside each high speed segment
|
||||||
|
highspeedSegments.forEach(highspeedSegment => {
|
||||||
|
var highestSpeed = 0;
|
||||||
|
var highestSpeedSegmentNumber = 0;
|
||||||
|
for (var i = highspeedSegment.startingSegmentNumber; i < highspeedSegment.startingSegmentNumber + highspeedSegment.segmentLength; i++) {
|
||||||
|
if (path[i].requiredSpeed > highestSpeed) {
|
||||||
|
highestSpeed = path[i].requiredSpeed;
|
||||||
|
highestSpeedSegmentNumber = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
highspeedSegment.highestSpeed = highestSpeed * 3.6;
|
||||||
|
highspeedSegment.highestSpeedSegmentNumber = highestSpeedSegmentNumber;
|
||||||
|
});
|
||||||
|
|
||||||
|
// We probably want to drop the segments where we're not at least doubling the minimum speed, and we want them to be at least three or four long
|
||||||
|
highspeedSegments = highspeedSegments.filter(segment => segment.highestSpeed >= 2.0 * minimumSpeed && segment.segmentLength > 4);
|
||||||
|
|
||||||
|
// Add these segments to the gpx
|
||||||
|
highspeedSegments.forEach(highspeedSegment => {
|
||||||
|
let firstSegment = path[highspeedSegment.startingSegmentNumber];
|
||||||
|
let lastSegment = path[highspeedSegment.startingSegmentNumber + highspeedSegment.segmentLength - 1];
|
||||||
|
let fastestSegment = path[highspeedSegment.highestSpeedSegmentNumber];
|
||||||
|
|
||||||
|
createWaypoint(gpxDocument, gpxDocument.documentElement, 'Accelerate to ' + highspeedSegment.highestSpeed.toFixed(1) + ' km/h', firstSegment.start, '#00FF00');
|
||||||
|
createWaypoint(gpxDocument, gpxDocument.documentElement, 'Reach ' + highspeedSegment.highestSpeed.toFixed(1) + ' km/h', fastestSegment.start, '#FFFF00');
|
||||||
|
createWaypoint(gpxDocument, gpxDocument.documentElement, 'High speed ends', lastSegment.start, '#FF0000');
|
||||||
|
});
|
||||||
|
|
||||||
var element = document.createElement('a');
|
var element = document.createElement('a');
|
||||||
element.setAttribute('href', 'data:application/gpx+xml;base64,' + btoa('<?xml version="1.0" encoding="utf-8"?>' + new XMLSerializer().serializeToString(gpxDocument)));
|
element.setAttribute('href', 'data:application/gpx+xml;base64,' + btoa('<?xml version="1.0" encoding="utf-8"?>' + new XMLSerializer().serializeToString(gpxDocument)));
|
||||||
element.setAttribute('download', 'freewheeling-route.gpx');
|
element.setAttribute('download', 'freewheeling-route.gpx');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user