diff --git a/.gitignore b/.gitignore index 5dc90e4..c3e3c1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.vscode/ dist/ native/* node_modules/ diff --git a/index.html b/index.html index 590a068..e5955ef 100644 --- a/index.html +++ b/index.html @@ -63,6 +63,9 @@
+
+ +
diff --git a/native/route_search.cpp b/native/route_search.cpp index d37ac92..da12c20 100644 --- a/native/route_search.cpp +++ b/native/route_search.cpp @@ -15,6 +15,7 @@ const float GRAVITY_ACCELERATION = 9.81; struct Connection { int connected_point_number; float distance; + float course; uint8_t speed_limit; bool motorway; bool tunnel; @@ -64,6 +65,7 @@ struct JSSearchResult { struct ListNode { int id; float current_speed; + float current_course; ListNode* next = NULL; }; @@ -93,6 +95,7 @@ struct CurrentAreaSearch { bool allowMotorways; bool allowTunnels; bool allowAgainstOneway; + bool limitCornerSpeed; std::vector startNodes; size_t startNodeCounter = 0; @@ -121,10 +124,12 @@ void addLinkToRoadNode(RoadNode* roadNodes, int node_from, int node_to, uint8_t float to_y = roadNodes[node_to].position_y; float distance = sqrt(pow(to_x - from_x, 2) + pow(to_y - from_y, 2)); + float course = atan2(to_x - from_x, to_y - from_y) * 180 / 3.14152965; Connection connection; connection.connected_point_number = node_to; connection.distance = distance; + connection.course = course; connection.speed_limit = speed_limit; connection.motorway = motorway; connection.tunnel = tunnel; @@ -302,7 +307,7 @@ void getNeighbourConnections(RoadNode node, Connection* targetArray, int &number } } -SearchResult findAllPathsFromPoint(int startingNode, float minimum_speed, float maximum_speed, int maximumSpeedLimit, float drag_coefficient, bool allowMotorways, bool allowTunnels, bool allowAgainstOneway) { +SearchResult findAllPathsFromPoint(int startingNode, float minimum_speed, float maximum_speed, int maximumSpeedLimit, float drag_coefficient, bool allowMotorways, bool allowTunnels, bool allowAgainstOneway, bool limitCornerSpeed) { SearchResult result; result.startingNode = startingNode; @@ -313,10 +318,10 @@ SearchResult findAllPathsFromPoint(int startingNode, float minimum_speed, float result.reachableNodes[startingNode] = firstNodeInfo; ListNode *nextNode = new ListNode; - ListNode *lastNode = nextNode; nextNode->id = startingNode; nextNode->current_speed = minimum_speed; + nextNode->current_course = 0; while (nextNode != NULL) { ListNode *currentNode = nextNode; @@ -324,12 +329,9 @@ SearchResult findAllPathsFromPoint(int startingNode, float minimum_speed, float int currentId = currentNode->id; float currentSpeed = currentNode->current_speed; + float currentCourse = currentNode->current_course; RoadNode bestNode = set.roadNodes[currentId]; - - if (lastNode == currentNode) { - lastNode = NULL; - } delete currentNode; Connection neighbours[10]; @@ -366,6 +368,21 @@ SearchResult findAllPathsFromPoint(int startingNode, float minimum_speed, float if (resultingSpeed < 0) { continue; } + + // If we limit the speed on corners, do that here + if (limitCornerSpeed) { + float courseDifference = fabs(currentCourse - neighbour.course); + if (courseDifference > 180.0) { + courseDifference = 360 - courseDifference; + } + + if (courseDifference > 95) { + resultingSpeed = minimum_speed; + } else if (courseDifference > 45.0) { + float maximumCornerSpeed = (95 - courseDifference) / 50.0 * (maximum_speed - minimum_speed) + minimum_speed; + resultingSpeed = fmin(resultingSpeed, maximumCornerSpeed); + } + } // Check if this node is already in the reachable nodes map auto resultIterator = result.reachableNodes.find(neighbour.connected_point_number); @@ -383,6 +400,7 @@ SearchResult findAllPathsFromPoint(int startingNode, float minimum_speed, float ListNode *neighbourListNode = new ListNode; neighbourListNode->id = neighbour.connected_point_number; neighbourListNode->current_speed = reachableNodeInfo.currentSpeed; + neighbourListNode->current_course = neighbour.course; if (nextNode == NULL || resultingSpeed < nextNode->current_speed) { neighbourListNode->next = nextNode; @@ -405,8 +423,8 @@ SearchResult findAllPathsFromPoint(int startingNode, float minimum_speed, float return result; } -JSSearchResult findAllPathsFromPointJS(int startingNode, float minimumSpeed, float maximumSpeed, int maximumSpeedLimit, float dragCoefficient, bool allowMotorways, bool allowTunnels, bool allowAgainstOneway) { - lastSearchResult = findAllPathsFromPoint(startingNode, minimumSpeed, maximumSpeed, maximumSpeedLimit, dragCoefficient, allowMotorways, allowTunnels, allowAgainstOneway); +JSSearchResult findAllPathsFromPointJS(int startingNode, float minimumSpeed, float maximumSpeed, int maximumSpeedLimit, float dragCoefficient, bool allowMotorways, bool allowTunnels, bool allowAgainstOneway, bool limitCornerSpeed) { + lastSearchResult = findAllPathsFromPoint(startingNode, minimumSpeed, maximumSpeed, maximumSpeedLimit, dragCoefficient, allowMotorways, allowTunnels, allowAgainstOneway, limitCornerSpeed); float start_x = set.roadNodes[startingNode].position_x; float start_y = set.roadNodes[startingNode].position_y; @@ -721,7 +739,7 @@ std::vector findPossibleStartNodes(float minimumSpeed, float maximumSp return possibleStartNodes; } -AreaSearchResult startAreaSearch(float minimumSpeed, float maximumSpeed, float maximumSpeedLimit, float dragCoefficient, bool allowMotorways, bool allowTunnels, bool allowAgainstOneway, std::vector>> searchArea) { +AreaSearchResult startAreaSearch(float minimumSpeed, float maximumSpeed, float maximumSpeedLimit, float dragCoefficient, bool allowMotorways, bool allowTunnels, bool allowAgainstOneway, bool limitCornerSpeed, std::vector>> searchArea) { currentAreaSearch = CurrentAreaSearch(); currentAreaSearch.startNodes = findPossibleStartNodes(minimumSpeed, maximumSpeedLimit, dragCoefficient, allowMotorways, allowTunnels, allowAgainstOneway, searchArea); currentAreaSearch.minimumSpeed = minimumSpeed; @@ -731,6 +749,7 @@ AreaSearchResult startAreaSearch(float minimumSpeed, float maximumSpeed, float m currentAreaSearch.allowMotorways = allowMotorways; currentAreaSearch.allowTunnels = allowTunnels; currentAreaSearch.allowAgainstOneway = allowAgainstOneway; + currentAreaSearch.limitCornerSpeed = limitCornerSpeed; AreaSearchResult result; result.remainingNodes = currentAreaSearch.startNodes.size(); @@ -747,7 +766,8 @@ AreaSearchResult continueAreaSearch() { currentAreaSearch.dragCoefficient, currentAreaSearch.allowMotorways, currentAreaSearch.allowTunnels, - currentAreaSearch.allowAgainstOneway + currentAreaSearch.allowAgainstOneway, + currentAreaSearch.limitCornerSpeed ); // Remove all nodes we have reached from here as possible future start nodes diff --git a/src/interfaces.ts b/src/interfaces.ts index 4c6f8eb..f1e5ca7 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -44,7 +44,8 @@ interface FindPathsFromNode { dragCoefficient: number, allowMotorways: boolean, allowTunnels: boolean, - allowAgainstOneway: boolean + allowAgainstOneway: boolean, + limitCornerSpeed: boolean } export interface Endpoint { @@ -102,7 +103,8 @@ interface SearchArea { dragCoefficient: number, allowMotorways: boolean, allowTunnels: boolean, - allowAgainstOneway: boolean + allowAgainstOneway: boolean, + limitCornerSpeed: boolean } interface ContinueSearch { diff --git a/src/main.ts b/src/main.ts index 3fd9499..7ccc21c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -16,6 +16,7 @@ interface Settings { allowMotorways: boolean, allowTunnels: boolean, allowAgainstOneway: boolean, + limitCornerSpeed: boolean, cutoffDistance: number } @@ -27,6 +28,7 @@ const DEFAULT_DRAG_COEFFICIENT = 0.005; const DEFAULT_ALLOW_MOTORWAYS = false; const DEFAULT_ALLOW_TUNNELS = false; const DEFAULT_ALLOW_AGAINST_ONE_WAY = false; +const DEFAULT_LIMIT_CORNER_SPEED = true; const DEFAULT_CUTOFF_DISTANCE = 1000; // Set up variables @@ -58,6 +60,7 @@ let dragCoefficientInput = document.getElementById('drag-coefficient-input'); let allowMotorwaysInput = document.getElementById('allow-motorways-input'); let allowTunnelsInput = document.getElementById('allow-tunnels-input'); let allowAgainstOnewayInput = document.getElementById('allow-wrong-way-input'); +let limitCornerSpeedInput = document.getElementById('limit-corner-speed-input'); let cutoffDistanceInput = document.getElementById('cutoff-distance-input'); @@ -79,7 +82,8 @@ routeWorker.onmessage = e => { dragCoefficient: settings.dragCoefficient, allowMotorways: settings.allowMotorways, allowTunnels: settings.allowTunnels, - allowAgainstOneway: settings.allowAgainstOneway + allowAgainstOneway: settings.allowAgainstOneway, + limitCornerSpeed: settings.limitCornerSpeed }}; routeWorker.postMessage(findPathsMessage); } else if (message.foundPathsFromNode != null) { @@ -137,7 +141,8 @@ routeWorker.onmessage = e => { dragCoefficient: settings.dragCoefficient, allowMotorways: settings.allowMotorways, allowTunnels: settings.allowTunnels, - allowAgainstOneway: settings.allowAgainstOneway + allowAgainstOneway: settings.allowAgainstOneway, + limitCornerSpeed: settings.limitCornerSpeed } }; routeWorker.postMessage(requestMessage); @@ -189,7 +194,8 @@ function setUpMapHandler() { dragCoefficient: settings.dragCoefficient, allowMotorways: settings.allowMotorways, allowTunnels: settings.allowTunnels, - allowAgainstOneway: settings.allowAgainstOneway + allowAgainstOneway: settings.allowAgainstOneway, + limitCornerSpeed: settings.limitCornerSpeed }}; routeWorker.postMessage(newRoutesMessage); } @@ -306,6 +312,7 @@ setUpNumberInput(dragCoefficientInput, 'drag-coefficient', DEFAULT_DRAG_COEFFICI setUpBooleanInput(allowMotorwaysInput, 'allow-motorways', DEFAULT_ALLOW_MOTORWAYS); setUpBooleanInput(allowTunnelsInput, 'allow-tunnels', DEFAULT_ALLOW_TUNNELS); setUpBooleanInput(allowAgainstOnewayInput, 'allow-against-one-way', DEFAULT_ALLOW_AGAINST_ONE_WAY); +setUpBooleanInput(limitCornerSpeedInput, 'limit-corner-speed', DEFAULT_LIMIT_CORNER_SPEED); setUpNumberInput(cutoffDistanceInput, 'cutoff-distance', DEFAULT_CUTOFF_DISTANCE); function getSettings(): Settings { @@ -317,6 +324,7 @@ function getSettings(): Settings { allowMotorways: getBooleanValue(allowMotorwaysInput, DEFAULT_ALLOW_MOTORWAYS), allowTunnels: getBooleanValue(allowTunnelsInput, DEFAULT_ALLOW_TUNNELS), allowAgainstOneway: getBooleanValue(allowAgainstOnewayInput, DEFAULT_ALLOW_AGAINST_ONE_WAY), + limitCornerSpeed: getBooleanValue(limitCornerSpeedInput, DEFAULT_LIMIT_CORNER_SPEED), cutoffDistance: getNumberValue(cutoffDistanceInput, DEFAULT_CUTOFF_DISTANCE) }; } @@ -329,6 +337,7 @@ function enableSettings(): void { enableInput(allowMotorwaysInput); enableInput(allowTunnelsInput); enableInput(allowAgainstOnewayInput); + enableInput(limitCornerSpeedInput); } function disableSettings(): void { @@ -339,6 +348,7 @@ function disableSettings(): void { disableInput(allowMotorwaysInput); disableInput(allowTunnelsInput); disableInput(allowAgainstOnewayInput); + disableInput(limitCornerSpeedInput); } @@ -356,7 +366,8 @@ searchButton?.addEventListener('click', _ => { dragCoefficient: settings.dragCoefficient, allowMotorways: settings.allowMotorways, allowTunnels: settings.allowTunnels, - allowAgainstOneway: settings.allowAgainstOneway + allowAgainstOneway: settings.allowAgainstOneway, + limitCornerSpeed: settings.limitCornerSpeed }}; routeWorker.postMessage(message); } diff --git a/src/modules/worker/worker.ts b/src/modules/worker/worker.ts index c2e9fdd..64416de 100644 --- a/src/modules/worker/worker.ts +++ b/src/modules/worker/worker.ts @@ -102,7 +102,8 @@ onmessage = async (e) => { message.findPathsFromNode.dragCoefficient, message.findPathsFromNode.allowMotorways, message.findPathsFromNode.allowTunnels, - message.findPathsFromNode.allowAgainstOneway + message.findPathsFromNode.allowAgainstOneway, + message.findPathsFromNode.limitCornerSpeed ); let endpoints: Endpoint[] = []; @@ -186,6 +187,7 @@ onmessage = async (e) => { settings.allowMotorways, settings.allowTunnels, settings.allowAgainstOneway, + settings.limitCornerSpeed, createCMultiPolygon(module, settings.polygons) );