LCOV - code coverage report
Current view: top level - src/utils/router - AStarLookupTable.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 84.6 % 195 165
Test Date: 2025-05-19 15:30:56 Functions: 43.3 % 30 13

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2012-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    AStarLookupTable.h
      15              : /// @author  Jakob Erdmann
      16              : /// @date    July 2017
      17              : ///
      18              : // Precomputed landmark distances to speed up the A* routing algorithm
      19              : /****************************************************************************/
      20              : #pragma once
      21              : #include <config.h>
      22              : 
      23              : #include <iostream>
      24              : #include <fstream>
      25              : #ifdef HAVE_ZLIB
      26              : #include <foreign/zstr/zstr.hpp>
      27              : #endif
      28              : #ifdef HAVE_FOX
      29              : #include <utils/foxtools/MFXWorkerThread.h>
      30              : #endif
      31              : #include <utils/common/MapMatcher.h>
      32              : #include <utils/geom/PositionVector.h>
      33              : #include <utils/router/ReversedEdge.h>
      34              : #include <utils/router/SUMOAbstractRouter.h>
      35              : 
      36              : #define UNREACHABLE (std::numeric_limits<double>::max() / 1000.0)
      37              : 
      38              : //#define ASTAR_DEBUG_LOOKUPTABLE
      39              : //#define ASTAR_DEBUG_LOOKUPTABLE_FROM "disabled"
      40              : //#define ASTAR_DEBUG_UNREACHABLE
      41              : 
      42              : // ===========================================================================
      43              : // class definitions
      44              : // ===========================================================================
      45              : /**
      46              :  * @class LandmarkLookupTable
      47              :  * @brief Computes the shortest path through a network using the A* algorithm.
      48              :  *
      49              :  * The template parameters are:
      50              :  * @param E The edge class to use (MSEdge/ROEdge)
      51              :  * @param V The vehicle class to use (MSVehicle/ROVehicle)
      52              :  * @param PF The prohibition function to use (prohibited_withPermissions/noProhibitions)
      53              :  * @param EC The class to retrieve the effort for an edge from
      54              :  *
      55              :  * The router is edge-based. It must know the number of edges for internal reasons
      56              :  *  and whether a missing connection between two given edges (unbuild route) shall
      57              :  *  be reported as an error or as a warning.
      58              :  *
      59              :  */
      60              : 
      61              : template<class E, class V>
      62              : class AbstractLookupTable {
      63              : public:
      64              :     virtual ~AbstractLookupTable() {}
      65              : 
      66              :     /// @brief provide a lower bound on the distance between from and to (excluding traveltime of both edges)
      67              :     virtual double lowerBound(const E* from, const E* to, double speed, double speedFactor, double fromEffort, double toEffort) const = 0;
      68              : 
      69              :     /// @brief whether the heuristic ist consistent (found nodes are always visited on the shortest path the first time)
      70              :     virtual bool consistent() const = 0;
      71              : };
      72              : 
      73              : 
      74              : template<class E, class V>
      75              : class FullLookupTable : public AbstractLookupTable<E, V> {
      76              : public:
      77            0 :     FullLookupTable(const std::string& filename, const int size) :
      78            0 :         myTable(size) {
      79            0 :         std::ifstream strm(filename.c_str());
      80            0 :         for (int i = 0; i < size; i++) {
      81            0 :             for (int j = 0; j < size; j++) {
      82              :                 double val;
      83              :                 strm >> val;
      84            0 :                 myTable[i].push_back(val);
      85              :             }
      86              :         }
      87            0 :     }
      88              : 
      89            0 :     virtual ~FullLookupTable() {
      90            0 :     }
      91              : 
      92            0 :     double lowerBound(const E* from, const E* to, double /*speed*/, double speedFactor, double /*fromEffort*/, double /*toEffort*/) const {
      93            0 :         return myTable[from->getNumericalID()][to->getNumericalID()] / speedFactor;
      94              :     }
      95              : 
      96            0 :     bool consistent() const {
      97            0 :         return true;
      98              :     }
      99              : 
     100              : private:
     101              :     std::vector<std::vector<double> > myTable;
     102              : };
     103              : 
     104              : 
     105              : template<class E, class V, class M>
     106              : class LandmarkLookupTable : public AbstractLookupTable<E, V> {
     107              : public:
     108           55 :     LandmarkLookupTable(const std::string& filename, const std::vector<E*>& edges, SUMOAbstractRouter<E, V>* router,
     109              :                         SUMOAbstractRouter<ReversedEdge<E, V>, V>* reverseRouter,
     110           55 :                         const V* defaultVehicle, const std::string& outfile, const int maxNumThreads, M* mapMatcher) {
     111           55 :         myFirstNonInternal = -1;
     112              :         std::map<std::string, int> numericID;
     113              :         bool haveTaz = false;
     114       105391 :         for (E* e : edges) {
     115       105336 :             if (!e->isInternal()) {
     116        19248 :                 if (myFirstNonInternal == -1) {
     117           55 :                     myFirstNonInternal = e->getNumericalID();
     118              :                 }
     119        19248 :                 if (e->isTazConnector()) {
     120              :                     haveTaz = true;
     121              :                 }
     122        19248 :                 numericID[e->getID()] = e->getNumericalID() - myFirstNonInternal;
     123              :             }
     124              :         }
     125              : #ifdef HAVE_ZLIB
     126          116 :         zstr::ifstream strm(filename.c_str(), std::fstream::in | std::fstream::binary);
     127              : #else
     128              :         std::ifstream strm(filename.c_str());
     129              : #endif
     130           55 :         if (!strm.good()) {
     131            0 :             throw ProcessError(TLF("Could not load landmark-lookup-table from '%'.", filename));
     132              :         }
     133              :         std::string line;
     134              :         std::vector<const E*> landmarks;
     135              :         int numLandMarks = 0;
     136              :         bool haveData = false;
     137        21965 :         while (std::getline(strm, line)) {
     138        10956 :             if (line == "") {
     139              :                 break;
     140              :             }
     141        10956 :             StringTokenizer st(line);
     142        10956 :             if (st.size() == 1) {
     143           72 :                 const std::string lm = st.get(0);
     144              :                 if (myLandmarks.count(lm) != 0) {
     145            0 :                     throw ProcessError(TLF("Duplicate edge '%' in landmark file.", lm));
     146              :                 }
     147              :                 // retrieve landmark edge
     148              :                 const auto& it = numericID.find(lm);
     149           72 :                 if (it == numericID.end()) {
     150            6 :                     throw ProcessError(TLF("Landmark edge '%' does not exist in the network.", lm));
     151              :                 }
     152           70 :                 myLandmarks[lm] = numLandMarks++;
     153          140 :                 myFromLandmarkDists.push_back(std::vector<double>(0));
     154          142 :                 myToLandmarkDists.push_back(std::vector<double>(0));
     155           70 :                 landmarks.push_back(edges[it->second + myFirstNonInternal]);
     156        10884 :             } else if (st.size() == 2) {
     157              :                 // geo landmark
     158              :                 try {
     159            8 :                     std::string lonStr = st.get(0);
     160            8 :                     if (!lonStr.empty() && lonStr.back() == ',') {
     161              :                         // remove trailing comma
     162            8 :                         lonStr = lonStr.substr(0, lonStr.size() - 1);
     163              :                     }
     164            8 :                     double lon = StringUtils::toDouble(lonStr);
     165           16 :                     double lat = StringUtils::toDouble(st.get(1));
     166              :                     std::vector<const E*> mapped;
     167              :                     bool ok;
     168            8 :                     mapMatcher->parseGeoEdges(PositionVector({Position(lon, lat)}), true, SVC_IGNORING, mapped, "LMLT", false, ok, true);
     169            8 :                     if (mapped.size() != 1) {
     170            0 :                         throw ProcessError(TLF("Invalid coordinate in landmark file, could not find edge at  '%'", line));
     171              :                     }
     172            8 :                     std::string lm = mapped.front()->getID();
     173              :                     const auto& it = numericID.find(lm);
     174            8 :                     if (it == numericID.end()) {
     175            0 :                         throw ProcessError(TLF("Landmark edge '%' does not exist in the network.", lm));
     176              :                     }
     177            8 :                     myLandmarks[lm] = numLandMarks++;
     178           16 :                     myFromLandmarkDists.push_back(std::vector<double>(0));
     179           16 :                     myToLandmarkDists.push_back(std::vector<double>(0));
     180            8 :                     landmarks.push_back(edges[it->second + myFirstNonInternal]);
     181            8 :                 } catch (const NumberFormatException&) {
     182            0 :                     throw ProcessError(TLF("Broken landmark file, could not parse '%' as coordinates.", line));
     183              :                 }
     184        10876 :             } else if (st.size() == 4) {
     185              :                 // legacy style landmark table
     186         9436 :                 const std::string lm = st.get(0);
     187         9436 :                 const std::string edge = st.get(1);
     188         9436 :                 if (numericID[edge] != (int)myFromLandmarkDists[myLandmarks[lm]].size()) {
     189            0 :                     throw ProcessError(TLF("Unknown or unordered edge '%' in landmark file.", edge));
     190              :                 }
     191         9436 :                 const double distFrom = StringUtils::toDouble(st.get(2));
     192         9436 :                 const double distTo = StringUtils::toDouble(st.get(3));
     193         9436 :                 myFromLandmarkDists[myLandmarks[lm]].push_back(distFrom);
     194         9436 :                 myToLandmarkDists[myLandmarks[lm]].push_back(distTo);
     195              :                 haveData = true;
     196              :             } else {
     197         1440 :                 const std::string edge = st.get(0);
     198         1440 :                 if ((int)st.size() != 2 * numLandMarks + 1) {
     199            0 :                     throw ProcessError(TLF("Broken landmark file, unexpected number of entries (%) for edge '%'.", st.size() - 1, edge));
     200              :                 }
     201         1440 :                 if (numericID[edge] != (int)myFromLandmarkDists[0].size()) {
     202            0 :                     throw ProcessError(TLF("Unknown or unordered edge '%' in landmark file.", edge));
     203              :                 }
     204         4320 :                 for (int i = 0; i < numLandMarks; i++) {
     205         2880 :                     const double distFrom = StringUtils::toDouble(st.get(2 * i + 1));
     206         2880 :                     const double distTo = StringUtils::toDouble(st.get(2 * i + 2));
     207         2880 :                     myFromLandmarkDists[i].push_back(distFrom);
     208         2880 :                     myToLandmarkDists[i].push_back(distTo);
     209              :                 }
     210              :                 haveData = true;
     211              :             }
     212              :         }
     213           53 :         if (myLandmarks.empty()) {
     214           42 :             WRITE_WARNINGF("No landmarks in '%', falling back to standard A*.", filename);
     215              :             return;
     216              :         }
     217              : #ifdef HAVE_FOX
     218           39 :         MFXWorkerThread::Pool threadPool;
     219              :         std::vector<RoutingTask*> currentTasks;
     220              : #endif
     221           39 :         if (!haveData) {
     222           44 :             WRITE_MESSAGE(TL("Calculating new lookup table."));
     223              :         }
     224          111 :         for (int i = 0; i < numLandMarks; ++i) {
     225           76 :             if ((int)myFromLandmarkDists[i].size() != (int)edges.size() - myFirstNonInternal) {
     226           48 :                 const E* const landmark = landmarks[i];
     227           48 :                 if (haveData) {
     228            4 :                     if (myFromLandmarkDists[i].empty()) {
     229            0 :                         WRITE_WARNINGF(TL("No lookup table for landmark edge '%', recalculating."), landmark->getID());
     230              :                     } else {
     231            6 :                         const std::string tazWarning = haveTaz ? " Make sure that any used taz or junction-taz definitions are loaded when generating the table" : "";
     232           12 :                         throw ProcessError(TLF("Not all network edges were found in the lookup table '%' for landmark edge '%'.%", filename, landmark->getID(), tazWarning));
     233              :                     }
     234              :                 }
     235              : #ifdef HAVE_FOX
     236           44 :                 if (maxNumThreads > 0) {
     237            8 :                     const double lmCost = router->recomputeCosts({landmark}, defaultVehicle, 0);
     238              :                     router->setAutoBulkMode(true);
     239            8 :                     if (threadPool.size() == 0) {
     240            4 :                         if (reverseRouter == nullptr) {
     241              :                             // The CHRouter needs initialization
     242              :                             // before it gets cloned, so we do a dummy routing which is not in parallel
     243              :                             std::vector<const E*> route;
     244            0 :                             router->compute(landmark, landmark, defaultVehicle, 0, route, true);
     245            0 :                         } else {
     246              :                             reverseRouter->setAutoBulkMode(true);
     247              :                         }
     248           12 :                         while ((int)threadPool.size() < maxNumThreads) {
     249            8 :                             auto revClone = reverseRouter == nullptr ? nullptr : reverseRouter->clone();
     250            8 :                             new WorkerThread(threadPool, router->clone(), revClone, defaultVehicle);
     251              :                         }
     252              :                     }
     253         2208 :                     for (int j = (int)myFromLandmarkDists[i].size() + myFirstNonInternal; j < (int)edges.size(); ++j) {
     254         2200 :                         const E* const edge = edges[j];
     255         2200 :                         if (landmark != edge) {
     256         2192 :                             const double sourceDestCost = lmCost + router->recomputeCosts({edge}, defaultVehicle, 0);
     257         2192 :                             currentTasks.push_back(new RoutingTask(landmark, edge, sourceDestCost));
     258         2192 :                             threadPool.add(currentTasks.back(), i % maxNumThreads);
     259              :                         }
     260              :                     }
     261              :                 }
     262              : #else
     263              :                 UNUSED_PARAMETER(reverseRouter);
     264              : #endif
     265              :             }
     266              :         }
     267              : #ifdef HAVE_FOX
     268           35 :         threadPool.waitAll(false);
     269              :         int taskIndex = 0;
     270              : #endif
     271          105 :         for (int i = 0; i < numLandMarks; ++i) {
     272           70 :             if ((int)myFromLandmarkDists[i].size() != (int)edges.size() - myFirstNonInternal) {
     273           44 :                 const E* landmark = landmarks[i];
     274           44 :                 const double lmCost = router->recomputeCosts({landmark}, defaultVehicle, 0);
     275              :                 int unreachableFrom = 0;
     276              :                 int unreachableTo = 0;
     277        14580 :                 for (int j = (int)myFromLandmarkDists[i].size() + myFirstNonInternal; j < (int)edges.size(); ++j) {
     278        14536 :                     const E* const edge = edges[j];
     279        14536 :                     double distFrom = -1;
     280        14536 :                     double distTo = -1;
     281        14536 :                     if (landmark == edge) {
     282           44 :                         distFrom = 0;
     283           44 :                         distTo = 0;
     284              :                     } else {
     285        14492 :                         if (maxNumThreads > 0) {
     286              : #ifdef HAVE_FOX
     287         2192 :                             distFrom = currentTasks[taskIndex]->getFromCost();
     288         2192 :                             distTo = currentTasks[taskIndex]->getToCost();
     289         2192 :                             delete currentTasks[taskIndex++];
     290              : #endif
     291              :                         } else {
     292        12300 :                             const double sourceDestCost = lmCost + router->recomputeCosts({edge}, defaultVehicle, 0);
     293              :                             std::vector<const E*> route;
     294              :                             std::vector<const ReversedEdge<E, V>*> reversedRoute;
     295              :                             // compute from-distance (skip taz-sources and other unreachable edges)
     296        12300 :                             if (edge->getPredecessors().size() > 0 && landmark->getSuccessors().size() > 0) {
     297        11844 :                                 if (router->compute(landmark, edge, defaultVehicle, 0, route, true)) {
     298        23564 :                                     distFrom = MAX2(0.0, router->recomputeCosts(route, defaultVehicle, 0) - sourceDestCost);
     299              :                                     route.clear();
     300              :                                 }
     301              :                             }
     302              :                             // compute to-distance (skip unreachable landmarks)
     303        12300 :                             if (landmark->getPredecessors().size() > 0 && edge->getSuccessors().size() > 0) {
     304        12174 :                                 if (router->compute(edge, landmark, defaultVehicle, 0, route, true)) {
     305        24100 :                                     distTo = MAX2(0.0, router->recomputeCosts(route, defaultVehicle, 0) - sourceDestCost);
     306              :                                     route.clear();
     307              :                                 }
     308              :                             }
     309        12300 :                         }
     310              :                     }
     311        14536 :                     myFromLandmarkDists[i].push_back(distFrom);
     312        14536 :                     myToLandmarkDists[i].push_back(distTo);
     313        14536 :                     if (!edge->isTazConnector()) {
     314        14480 :                         if (distFrom == -1) {
     315          980 :                             unreachableFrom++;
     316              :                         }
     317        14480 :                         if (distTo == -1) {
     318          444 :                             unreachableTo++;
     319              :                         }
     320              :                     }
     321              :                 }
     322           44 :                 if (unreachableFrom > 0 || unreachableTo > 0) {
     323           24 :                     WRITE_WARNINGF(TL("Landmark % is not reachable from % edges and is unable to reach % out of % total edges."),
     324              :                                    landmark->getID(), unreachableFrom, unreachableTo, numericID.size());
     325              :                 }
     326              :             }
     327              :         }
     328           35 :         if (!outfile.empty()) {
     329              :             std::ostream* ostrm = nullptr;
     330              : #ifdef HAVE_ZLIB
     331           16 :             if (StringUtils::endsWith(outfile, ".gz")) {
     332            0 :                 ostrm = new zstr::ofstream(outfile.c_str(), std::ios_base::out);
     333              :             } else {
     334              : #endif
     335            8 :                 ostrm = new std::ofstream(outfile.c_str());
     336              : #ifdef HAVE_ZLIB
     337              :             }
     338              : #endif
     339            8 :             if (!ostrm->good()) {
     340            0 :                 delete ostrm;
     341            0 :                 throw ProcessError(TLF("Could not open file '%' for writing.", outfile));
     342              :             }
     343           24 :             WRITE_MESSAGEF(TL("Saving new matrix to '%'."), outfile);
     344           24 :             for (int i = 0; i < numLandMarks; ++i) {
     345           48 :                 (*ostrm) << getLandmark(i) << "\n";
     346              :             }
     347         2208 :             for (int j = 0; j < (int)myFromLandmarkDists[0].size(); ++j) {
     348         2200 :                 (*ostrm) << edges[j + myFirstNonInternal]->getID();
     349         6600 :                 for (int i = 0; i < numLandMarks; ++i) {
     350         8800 :                     (*ostrm) << " " << myFromLandmarkDists[i][j] << " " << myToLandmarkDists[i][j];
     351              :                 }
     352         2200 :                 (*ostrm) << "\n";
     353              :             }
     354            8 :             delete ostrm;
     355              :         }
     356          130 :     }
     357              : 
     358           49 :     virtual ~LandmarkLookupTable() {
     359           49 :     }
     360              : 
     361         5938 :     double lowerBound(const E* from, const E* to, double speed, double speedFactor, double fromEffort, double toEffort) const {
     362         5938 :         double result = from->getDistanceTo(to) / speed;
     363              : #ifdef ASTAR_DEBUG_LOOKUPTABLE
     364              :         if (from->getID() == ASTAR_DEBUG_LOOKUPTABLE_FROM) {
     365              :             std::cout << " lowerBound to=" << to->getID() << " result1=" << result << "\n";
     366              :         }
     367              : #endif
     368        14114 :         for (int i = 0; i < (int)myLandmarks.size(); ++i) {
     369              :             // a cost of -1 is used to encode unreachability.
     370         8180 :             const double fl = myToLandmarkDists[i][from->getNumericalID() - myFirstNonInternal];
     371         8180 :             const double tl = myToLandmarkDists[i][to->getNumericalID() - myFirstNonInternal];
     372         8180 :             if (fl >= 0 && tl >= 0) {
     373         4286 :                 const double bound = (fl - tl - toEffort) / speedFactor;
     374              : #ifdef ASTAR_DEBUG_LOOKUPTABLE
     375              :                 if (from->getID() == ASTAR_DEBUG_LOOKUPTABLE_FROM && result < bound) {
     376              :                     std::cout << "   landmarkTo=" << getLandmark(i) << " result2=" << bound
     377              :                               << " fl=" << fl << " tl=" << tl << "\n";
     378              :                 }
     379              : #endif
     380              :                 result = MAX2(result, bound);
     381              :             }
     382         8180 :             const double lt = myFromLandmarkDists[i][to->getNumericalID() - myFirstNonInternal];
     383         8180 :             const double lf = myFromLandmarkDists[i][from->getNumericalID() - myFirstNonInternal];
     384         8180 :             if (lt >= 0 && lf >= 0) {
     385         7744 :                 const double bound = (lt - lf - fromEffort) / speedFactor;
     386              : #ifdef ASTAR_DEBUG_LOOKUPTABLE
     387              :                 if (from->getID() == ASTAR_DEBUG_LOOKUPTABLE_FROM && result < bound) {
     388              :                     std::cout << "   landmarkFrom=" << getLandmark(i) << " result3=" << bound
     389              :                               << " lt=" << lt << " lf=" << lf << "\n";
     390              :                 }
     391              : #endif
     392              :                 result = MAX2(result, bound);
     393              :             }
     394         8180 :             if ((tl >= 0 && fl < 0)
     395         8180 :                     || (lf >= 0 && lt < 0)) {
     396              :                 // target unreachable.
     397              : #ifdef ASTAR_DEBUG_UNREACHABLE
     398              :                 std::cout << "   unreachable: from=" << from->getID() << " to=" << to->getID() << " landmark=" << getLandmark(i) << " "
     399              :                           << ((tl >= 0 && fl < 0) ? " (toLandmark)" : " (fromLandmark)")
     400              :                           << " fl=" << fl << " tl=" << tl << " lt=" << lt << " lf=" << lf
     401              :                           << "\n";
     402              : #endif
     403              :                 return UNREACHABLE;
     404              :             }
     405              :         }
     406              :         return result;
     407              :     }
     408              : 
     409           49 :     bool consistent() const {
     410           49 :         return false;
     411              :     }
     412              : 
     413              : private:
     414              :     std::map<std::string, int> myLandmarks;
     415              :     std::vector<std::vector<double> > myFromLandmarkDists;
     416              :     std::vector<std::vector<double> > myToLandmarkDists;
     417              :     int myFirstNonInternal;
     418              : 
     419              : #ifdef HAVE_FOX
     420              : private:
     421              :     class WorkerThread : public MFXWorkerThread {
     422              :     public:
     423            8 :         WorkerThread(MFXWorkerThread::Pool& pool,
     424              :                      SUMOAbstractRouter<E, V>* router,
     425              :                      SUMOAbstractRouter<ReversedEdge<E, V>, V>* reverseRouter, const V* vehicle)
     426            8 :             : MFXWorkerThread(pool), myRouter(router), myReversedRouter(reverseRouter), myVehicle(vehicle) {}
     427              : 
     428           16 :         virtual ~WorkerThread() {
     429            8 :             delete myRouter;
     430            8 :             delete myReversedRouter;
     431           24 :         }
     432              : 
     433         2192 :         const std::pair<double, double> compute(const E* src, const E* dest, const double costOff) {
     434              :             double fromResult = -1.;
     435         2192 :             if (myRouter->compute(src, dest, myVehicle, 0, myRoute, true)) {
     436         1702 :                 fromResult = MAX2(0.0, myRouter->recomputeCosts(myRoute, myVehicle, 0) + costOff);
     437              :                 myRoute.clear();
     438              :             }
     439              :             double toResult = -1.;
     440         2192 :             if (myReversedRouter != nullptr) {
     441         2192 :                 if (myReversedRouter->compute(src->getReversedRoutingEdge(), dest->getReversedRoutingEdge(), myVehicle, 0, myReversedRoute, true)) {
     442         1970 :                     toResult = MAX2(0.0, myReversedRouter->recomputeCosts(myReversedRoute, myVehicle, 0) + costOff);
     443              :                     myReversedRoute.clear();
     444              :                 }
     445              :             } else {
     446            0 :                 if (myRouter->compute(dest, src, myVehicle, 0, myRoute, true)) {
     447            0 :                     toResult = MAX2(0.0, myRouter->recomputeCosts(myRoute, myVehicle, 0) + costOff);
     448              :                     myRoute.clear();
     449              :                 }
     450              :             }
     451         2192 :             return std::make_pair(fromResult, toResult);
     452              :         }
     453              : 
     454              :     private:
     455              :         SUMOAbstractRouter<E, V>* myRouter;
     456              :         SUMOAbstractRouter<ReversedEdge<E, V>, V>* myReversedRouter;
     457              :         const V* myVehicle;
     458              :         std::vector<const E*> myRoute;
     459              :         std::vector<const ReversedEdge<E, V>*> myReversedRoute;
     460              :     };
     461              : 
     462              :     class RoutingTask : public MFXWorkerThread::Task {
     463              :     public:
     464         2192 :         RoutingTask(const E* src, const E* dest, const double costOff)
     465         2192 :             : mySrc(src), myDest(dest), myCostOff(-costOff) {}
     466         2192 :         void run(MFXWorkerThread* context) {
     467         2192 :             myCost = ((WorkerThread*)context)->compute(mySrc, myDest, myCostOff);
     468         2192 :         }
     469              :         double getFromCost() {
     470         2192 :             return myCost.first;
     471              :         }
     472              :         double getToCost() {
     473         2192 :             return myCost.second;
     474              :         }
     475              :     private:
     476              :         const E* const mySrc;
     477              :         const E* const myDest;
     478              :         const double   myCostOff;
     479              :         std::pair<double, double> myCost;
     480              :     private:
     481              :         /// @brief Invalidated assignment operator.
     482              :         RoutingTask& operator=(const RoutingTask&) = delete;
     483              :     };
     484              : 
     485              : private:
     486              :     /// @brief for multi threaded routing
     487              : #endif
     488              : 
     489           16 :     std::string getLandmark(int i) const {
     490           24 :         for (std::map<std::string, int>::const_iterator it = myLandmarks.begin(); it != myLandmarks.end(); ++it) {
     491           24 :             if (it->second == i) {
     492              :                 return it->first;
     493              :             }
     494              :         }
     495            0 :         return "";
     496              :     }
     497              : };
        

Generated by: LCOV version 2.0-1