#ifndef DIJKSTRA_H #define DIJKSTRA_H #include #include #include #include "DijkstraStructs.h" #include "../../misc/Debug.h" #include template class Dijkstra { /** all allocated nodes for the user-data inputs */ std::unordered_map*> nodes; /** all already processed edges */ std::unordered_set> usedEdges; /** to-be-processed nodes (USE LINKED LIST INSTEAD?!) */ std::vector*> toBeProcessedNodes; public: /** get (or create) a new node for the given user-node */ DijkstraNode* getNode(const T* userNode) { if (nodes.find(userNode) == nodes.end()) { DijkstraNode* dn = new DijkstraNode(userNode); nodes[userNode] = dn; } return nodes[userNode]; } /** get the edge (bi-directional) between the two given nodes */ DijkstraEdge getEdge(const DijkstraNode* n1, const DijkstraNode* n2) { return DijkstraEdge(n1, n2); } /** get the dijkstra-pendant for the given user-node */ DijkstraNode* getNode(const T& userNode) { return nodes[&userNode]; } /** build shortest path from start to end using the provided wrapper-class */ template void build(const T& start, const T& end, const Access& acc) { // NOTE: end is currently ignored! // runs until all nodes were evaluated Log::add("Dijkstra", "calculating dijkstra from " + (std::string)start); // cleanup toBeProcessedNodes.clear(); usedEdges.clear(); nodes.clear(); // run from start const T* cur = &start; // create a node for the start element DijkstraNode* dnStart = getNode(cur); dnStart->cumWeight = 0; // add this node to the processing list toBeProcessedNodes.push_back(dnStart); // until we are done while(!toBeProcessedNodes.empty()) { // get the next to-be-processed node DijkstraNode* dnSrc = toBeProcessedNodes[0]; // and remove him from the list toBeProcessedNodes.erase(toBeProcessedNodes.begin()); // process each neighbor of the current element for (int i = 0; i < acc.getNumNeighbors(*dnSrc->element); ++i) { // get the neighbor itself const T* dst = acc.getNeighbor(*dnSrc->element, i); // get the distance-weight to the neighbor const float weight = acc.getWeightBetween(*dnSrc->element, *dst); _assertTrue(weight >= 0, "edge-weight must not be negative!"); // get-or-create a node for the neighbor DijkstraNode* dnDst = getNode(dst); // get-or-create the edge describing the connection DijkstraEdge edge = getEdge(dnSrc, dnDst); // was this edge already processed? -> skip it if (usedEdges.find(edge) != usedEdges.end()) {continue;} // otherwise: remember it usedEdges.insert(edge); // and add the node for later processing toBeProcessedNodes.push_back(dnDst); // update the weight to the destination? const float potentialWeight = dnSrc->cumWeight + weight; if (potentialWeight < dnDst->cumWeight) { dnDst->cumWeight = potentialWeight; dnDst->previous = dnSrc; } } // sort the nodes by distance-from-start (shortest first) auto comp = [] (const DijkstraNode* n1, const DijkstraNode* n2) {return n1->cumWeight < n2->cumWeight;}; std::sort(toBeProcessedNodes.begin(), toBeProcessedNodes.end(), comp); } Log::add("Dijkstra", "processed " + std::to_string(nodes.size()) + " nodes"); // cleanup toBeProcessedNodes.clear(); usedEdges.clear(); } }; #endif // DIJKSTRA_H