#pragma once
#include <config.h>
#include <cassert>
#include <string>
#include <functional>
#include <vector>
#include <set>
#include <limits>
#include <algorithm>
#include <iterator>
#include <map>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <cstddef>
#include <utils/common/MsgHandler.h>
#include <utils/common/StringTokenizer.h>
#include <utils/common/StringUtils.h>
#include <utils/common/StdDefs.h>
#include <utils/common/ToString.h>
#include <utils/iodevices/OutputDevice.h>
#include "AStarLookupTable.h"
#include "SUMOAbstractRouter.h"
#include "KDTreePartition.h"
#include "FlippedEdge.h"
#include "AFInfo.h"
#include "AFBuilder.h"
#define UNREACHABLE (std::numeric_limits<double>::max() / 1000.0)
#define AFRO_WRITE_QGIS_FILTERS
#ifdef AFRO_DEBUG_LEVEL_3
#define AFRO_DEBUG_LEVEL_2
#endif
#ifdef AFRO_DEBUG_LEVEL_2
#define AFRO_DEBUG_LEVEL_1
#endif
#ifdef AFRO_DEBUG_LEVEL_1
#define AFRO_DEBUG_LEVEL_0
#endif
template<class E, class N, class V, class M>
class AFRouter : public SUMOAbstractRouter<E, V> {
public:
typedef AbstractLookupTable<E, V> LookupTable;
typedef typename KDTreePartition<E, N, V>::Cell Cell;
typedef typename AFInfo<E>::FlagInfo FlagInfo;
typedef AbstractLookupTable<FlippedEdge<E, N, V>, V> FlippedLookupTable;
typename SUMOAbstractRouter<E, V>::EdgeInfo* edgeInfo(const E* const edge) {
return &(this->myEdgeInfos[edge->getNumericalID()]);
}
const typename SUMOAbstractRouter<E, V>::EdgeInfo* edgeInfo(const E* const edge) const {
return &(this->myEdgeInfos[edge->getNumericalID()]);
}
class EdgeInfoComparator {
public:
bool operator()(const typename SUMOAbstractRouter<E, V>::EdgeInfo* edgeInfo1, const typename SUMOAbstractRouter<E, V>::EdgeInfo* edgeInfo2) const {
if (edgeInfo1->heuristicEffort == edgeInfo2->heuristicEffort) {
return edgeInfo1->edge->getNumericalID() > edgeInfo2->edge->getNumericalID();
}
return edgeInfo1->heuristicEffort > edgeInfo2->heuristicEffort;
}
};
AFRouter(const std::vector<E*>& edges,
const KDTreePartition<E, N, V>* partition,
bool unbuildIsWarning,
typename SUMOAbstractRouter<E, V>::Operation operation, typename SUMOAbstractRouter<FlippedEdge<E, N, V>, V>::Operation flippedOperation,
SUMOTime weightPeriod, const std::shared_ptr<const LookupTable> lookup = nullptr,
const std::shared_ptr<const FlippedLookupTable> flippedLookup = nullptr,
const bool havePermissions = false, const bool haveRestrictions = false) :
SUMOAbstractRouter<E, V>("arcFlagRouter", unbuildIsWarning, operation, nullptr, havePermissions, haveRestrictions),
myFlagInfos(nullptr),
myPartition(partition),
myLookupTable(lookup),
myMaxSpeed(NUMERICAL_EPS),
myWeightPeriod(weightPeriod),
myValidUntil(0),
myBuilder(new AFBuilder<E, N, V, M>(myPartition->getNumberOfLevels(), edges, unbuildIsWarning,
flippedOperation, flippedLookup, havePermissions, haveRestrictions)),
myType("arcFlagRouter"),
myQueryVisits(0),
myNumQueries(0),
myQueryStartTime(0),
myQueryTimeSum(0),
#ifdef AFRO_DEBUG_LEVEL_2
myFlagContextStartTime(0),
myFlagContextTimeSum(0),
#endif
myLastSettledEdgeCell(nullptr),
myTargetEdgeCellLevel0(nullptr) {
for (const E* const edge : edges) {
this->myEdgeInfos.push_back(typename SUMOAbstractRouter<E, V>::EdgeInfo(edge));
myMaxSpeed = MAX2(myMaxSpeed, edge->getSpeedLimit() * MAX2(1.0, edge->getLengthGeometryFactor()));
}
}
AFRouter(const std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo>& edgeInfos,
const std::vector<E*>& edges,
const KDTreePartition<E, N, V>* partition,
bool unbuildIsWarning,
typename SUMOAbstractRouter<E, V>::Operation operation,
typename SUMOAbstractRouter<FlippedEdge<E, N, V>, V>::Operation flippedOperation,
SUMOTime weightPeriod, const std::shared_ptr<const LookupTable> lookup = nullptr,
const std::shared_ptr<const FlippedLookupTable> flippedLookup = nullptr,
const bool havePermissions = false, const bool haveRestrictions = false) :
SUMOAbstractRouter<E, V>("arcFlagRouter", unbuildIsWarning, operation, nullptr, havePermissions, haveRestrictions),
myFlagInfos(nullptr),
myPartition(partition),
myLookupTable(lookup),
myMaxSpeed(NUMERICAL_EPS),
myWeightPeriod(weightPeriod),
myValidUntil(0),
myBuilder(new AFBuilder<E, N, V, M>(myPartition->getNumberOfLevels(), edges, unbuildIsWarning,
flippedOperation, flippedLookup, havePermissions, haveRestrictions)),
myType("arcFlagRouter"),
myQueryVisits(0),
myNumQueries(0),
myQueryStartTime(0),
myQueryTimeSum(0),
#ifdef AFRO_DEBUG_LEVEL_2
myFlagContextStartTime(0),
myFlagContextTimeSum(0),
#endif
myLastSettledEdgeCell(nullptr),
myTargetEdgeCellLevel0(nullptr) {
for (const auto& edgeInfo : edgeInfos) {
this->myEdgeInfos.push_back(typename SUMOAbstractRouter<E, V>::EdgeInfo(edgeInfo.edge));
myMaxSpeed = MAX2(myMaxSpeed, edgeInfo.edge->getSpeedLimit() * edgeInfo.edge->getLengthGeometryFactor());
}
}
AFRouter(const std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo>& edgeInfos,
const KDTreePartition<E, N, V>* partition,
bool unbuildIsWarning, typename SUMOAbstractRouter<E, V>::Operation operation,
std::vector<FlagInfo*>* flagInfos,
const std::shared_ptr<const LookupTable> lookup = nullptr,
const bool havePermissions = false, const bool haveRestrictions = false) :
SUMOAbstractRouter<E, V>("arcFlagRouterClone", unbuildIsWarning, operation, nullptr, havePermissions, haveRestrictions),
myFlagInfos(flagInfos),
myPartition(partition),
myLookupTable(lookup),
myMaxSpeed(NUMERICAL_EPS),
myWeightPeriod(SUMOTime_MAX),
myValidUntil(SUMOTime_MAX),
myBuilder(nullptr),
myType("arcFlagRouterClone"),
myQueryVisits(0),
myNumQueries(0),
myQueryStartTime(0),
myQueryTimeSum(0),
#ifdef AFRO_DEBUG_LEVEL_2
myFlagContextStartTime(0),
myFlagContextTimeSum(0),
#endif
myLastSettledEdgeCell(nullptr),
myTargetEdgeCellLevel0(nullptr) {
for (const auto& edgeInfo : edgeInfos) {
this->myEdgeInfos.push_back(typename SUMOAbstractRouter<E, V>::EdgeInfo(edgeInfo.edge));
myMaxSpeed = MAX2(myMaxSpeed, edgeInfo.edge->getSpeedLimit() * edgeInfo.edge->getLengthGeometryFactor());
}
}
virtual ~AFRouter() {
delete myBuilder;
}
virtual SUMOAbstractRouter<E, V>* clone() {
if (myWeightPeriod == SUMOTime_MAX && myFlagInfos != nullptr) {
return new AFRouter(this->myEdgeInfos, myPartition, this->myErrorMsgHandler == MsgHandler::getWarningInstance(),
this->myOperation, myFlagInfos, myLookupTable, this->myHavePermissions, this->myHaveRestrictions);
}
return new AFRouter(this->myEdgeInfos, myBuilder->getEdges(), myPartition,
this->myErrorMsgHandler == MsgHandler::getWarningInstance(),
this->myOperation, myBuilder->getArcFlagBuild()->getFlippedOperation(),
myWeightPeriod, myLookupTable, myBuilder->getArcFlagBuild()->getFlippedLookup(),
this->myHavePermissions, this->myHaveRestrictions);
}
static int partitionLevel2SHARCLevel(int partitionLevel, int numberOfPartitionLevels) {
if (partitionLevel <= 0) {
throw std::invalid_argument("partitionLevel2SHARCLevel: given partition level is zero (0) or below. This does not correspond to a valid SHARC level. Partition levels valid for conversion to SHARC levels go from one to number of partition levels minus one.");
}
if (partitionLevel > numberOfPartitionLevels - 1) {
throw std::invalid_argument("partitionLevel2SHARCLevel: given partition level exceeds the number of partition levels minus one. Most likely you did not start the partition level numbering at zero (0), which is required here.");
}
return (numberOfPartitionLevels - 1) - partitionLevel;
}
static int sHARCLevel2PartitionLevel(int sHARCLevel, int numberOfPartitionLevels) {
int numberOfSHARCLevels = numberOfPartitionLevels - 1;
if (sHARCLevel < 0) {
throw std::invalid_argument("sHARCLevel2PartitionLevel: given SHARC level is negative.");
}
if (sHARCLevel > numberOfSHARCLevels - 1) {
throw std::invalid_argument("sHARCLevel2PartitionLevel: given SHARC level exceeds the number of SHARC levels minus one. Most likely you did not start the SHARC level numbering at zero (0), which is required here.");
}
return numberOfSHARCLevels - sHARCLevel;
}
static bool flag(const FlagInfo* flagInfo, const std::tuple<int, int, bool> flagContext) {
assert(flagInfo);
return flagInfo->arcFlags.empty() ? true :
(flagInfo->arcFlags)[std::get<0>(flagContext) * 2
+ std::get<1>(flagContext) ];
}
std::vector<bool>& flags(const E* edge);
virtual void reset(const V* const vehicle) {
if (myValidUntil == 0) {
myValidUntil = myWeightPeriod;
}
assert(myBuilder);
#ifdef AFRO_DEBUG_LEVEL_0
long long int firstCallStart = 0;
long long int firstCallTime = 0;
firstCallStart = SysUtils::getCurrentMillis();
std::cout << "Calling arc flag router for the first time during current weight period (arc flags build). This might take a while... " << std::endl;
#endif
myFlagInfos = &(myBuilder->build(myValidUntil - myWeightPeriod, vehicle));
#ifdef AFRO_DEBUG_LEVEL_0
firstCallTime = (SysUtils::getCurrentMillis() - firstCallStart);
std::cout << "Time spent for arc flags build: " << elapsedMs2string(firstCallTime) << std::endl;
#endif
}
void init(const int edgeID, const SUMOTime msTime);
std::tuple<int, int, bool> flagContext(const E* settledEdge, const E* targetEdge);
std::tuple<int, int, bool> flagContextNaive(const E* settledEdge, const E* targetEdge);
bool compute(const E* from, const E* to, const V* const vehicle,
SUMOTime msTime, std::vector<const E*>& into, bool silent = false) {
assert(from != nullptr && to != nullptr);
if (this->myEdgeInfos[from->getNumericalID()].prohibited || this->isProhibited(from, vehicle)) {
if (!silent) {
this->myErrorMsgHandler->inform("Vehicle '" + Named::getIDSecure(vehicle) + "' is not allowed on source edge '" + from->getID() + "'.");
}
return false;
}
if (this->myEdgeInfos[to->getNumericalID()].prohibited || this->isProhibited(to, vehicle)) {
if (!silent) {
this->myErrorMsgHandler->inform("Vehicle '" + Named::getIDSecure(vehicle) + "' is not allowed on destination edge '" + to->getID() + "'.");
}
return false;
}
if (msTime >= myValidUntil) {
assert(myBuilder != nullptr);
while (msTime >= myValidUntil) {
myValidUntil += myWeightPeriod;
}
reset(vehicle);
}
msTime = myValidUntil - myWeightPeriod;
double length = 0.;
this->startQuery();
const SUMOVehicleClass vClass = vehicle == 0 ? SVC_IGNORING : vehicle->getVClass();
this->init(from->getNumericalID(), msTime);
this->myAmClean = false;
int num_visited = 0;
#ifdef AFRO_DEBUG_LEVEL_1
int numberOfFollowers = 0;
int numberOfAvoidedFollowers = 0;
int numberOfEmptyFlagVectors = 0;
#endif
const bool mayRevisit = myLookupTable != nullptr && !myLookupTable->consistent();
const double speed = vehicle == nullptr ? myMaxSpeed : MIN2(vehicle->getMaxSpeed(), myMaxSpeed * vehicle->getChosenSpeedFactor());
while (!this->myFrontierList.empty()) {
num_visited += 1;
auto* const minimumInfo = this->myFrontierList.front();
const E* const minEdge = minimumInfo->edge;
if (minEdge == to) {
this->buildPathFrom(minimumInfo, into);
this->endQuery(num_visited);
#ifdef AFRO_DEBUG_LEVEL_1
std::cout << "Found to, to->getID(): " << to->getID() << std::endl;
std::cout << static_cast<double>(numberOfFollowers - numberOfAvoidedFollowers) / static_cast<double>(num_visited)
<< " followers considered (out of " << static_cast<double>(numberOfFollowers) / static_cast<double>(num_visited) << ") on average." << std::endl;
std::cout << static_cast<double>(numberOfFollowers - numberOfAvoidedFollowers)
<< " followers considered (out of " << static_cast<double>(numberOfFollowers) << ")." << std::endl;
std::cout << numberOfEmptyFlagVectors << " out of " << numberOfFollowers << " flag vectors of followers were unassigned (i.e., empty)." << std::endl;
std::cout << "num_visited: " << num_visited << std::endl;
#endif
return true;
}
std::pop_heap(this->myFrontierList.begin(), this->myFrontierList.end(), myComparator);
this->myFrontierList.pop_back();
this->myFound.push_back(minimumInfo);
minimumInfo->visited = true;
const double effortDelta = this->getEffort(minEdge, vehicle, minimumInfo->leaveTime);
const double leaveTime = minimumInfo->leaveTime + this->getTravelTime(minEdge, vehicle, minimumInfo->leaveTime, effortDelta);
double heuristic_remaining = 0.;
double heuristicEffort = minimumInfo->effort + effortDelta + heuristic_remaining;
for (const std::pair<const E*, const E*>& follower : minEdge->getViaSuccessors(vClass)) {
auto& followerInfo = this->myEdgeInfos[follower.first->getNumericalID()];
const FlagInfo* followerFlagInfo = (*myFlagInfos)[follower.first->getNumericalID()];
if (followerInfo.prohibited || this->isProhibited(follower.first, vehicle)) {
continue;
}
#ifdef AFRO_DEBUG_LEVEL_1
numberOfFollowers++;
if (followerFlagInfo->arcFlags.empty()) {
numberOfEmptyFlagVectors++;
}
#endif
#ifdef AFRO_DEBUG_LEVEL_2
myFlagContextStartTime = SysUtils::getCurrentMillis();
#endif
std::tuple<int, int, bool> flagContext = this->flagContext(follower.first, to);
#ifdef AFRO_DEBUG_LEVEL_2
myFlagContextTimeSum += (SysUtils::getCurrentMillis() - myFlagContextStartTime);
#endif
if (!flag(followerFlagInfo, flagContext)) {
#ifdef AFRO_DEBUG_LEVEL_1
numberOfAvoidedFollowers++;
#endif
continue;
}
if (heuristic_remaining == 0 && std::get<0>(flagContext) == 0 && std::get<2>(flagContext)) {
heuristic_remaining =
(myLookupTable == nullptr ? minEdge->getDistanceTo(to) / speed :
myLookupTable->lowerBound(minEdge, to, speed, vehicle->getChosenSpeedFactor(),
minEdge->getMinimumTravelTime(nullptr), to->getMinimumTravelTime(nullptr)));
if (heuristic_remaining == UNREACHABLE) {
break;
}
heuristicEffort += heuristic_remaining;
}
double effort = minimumInfo->effort + effortDelta;
double time = leaveTime;
this->updateViaEdgeCost(follower.second, vehicle, time, effort, length);
const double oldEffort = followerInfo.effort;
if ((!followerInfo.visited || mayRevisit) && effort < oldEffort) {
followerInfo.effort = effort;
followerInfo.heuristicEffort = MAX2(MIN2(heuristicEffort, followerInfo.heuristicEffort), effort);
followerInfo.leaveTime = time;
followerInfo.prev = minimumInfo;
if (oldEffort == std::numeric_limits<double>::max()) {
this->myFrontierList.push_back(&followerInfo);
std::push_heap(this->myFrontierList.begin(), this->myFrontierList.end(), myComparator);
} else {
auto fi = std::find(this->myFrontierList.begin(), this->myFrontierList.end(), &followerInfo);
if (fi == this->myFrontierList.end()) {
assert(mayRevisit);
this->myFrontierList.push_back(&followerInfo);
std::push_heap(this->myFrontierList.begin(), this->myFrontierList.end(), myComparator);
} else {
std::push_heap(this->myFrontierList.begin(), fi + 1, myComparator);
}
}
}
}
}
this->endQuery(num_visited);
#ifdef AFRO_DEBUG_LEVEL_1
std::cout << "Queue ran empty, no solution." << std::endl;
std::cout << static_cast<double>(numberOfFollowers - numberOfAvoidedFollowers) / static_cast<double>(num_visited)
<< " followers considered (out of " << static_cast<double>(numberOfFollowers) / static_cast<double>(num_visited) << ") on average." << std::endl;
std::cout << static_cast<double>(numberOfFollowers - numberOfAvoidedFollowers)
<< " followers considered (out of " << static_cast<double>(numberOfFollowers) << ")." << std::endl;
std::cout << numberOfEmptyFlagVectors << " out of " << numberOfFollowers << " flag vectors of followers were unassigned (i.e., empty)." << std::endl;
std::cout << "num_visited: " << num_visited << std::endl;
#endif
if (!silent) {
this->myErrorMsgHandler->informf("No connection between edge '%' and edge '%' found.", from->getID(), to->getID());
}
return false;
}
void startQuery();
void endQuery(int visits);
void reportStatistics();
void resetStatistics();
virtual void setBulkMode(const bool mode) {
UNUSED_PARAMETER(mode);
throw std::runtime_error("Bulk mode is not supported by the arc flag router.");
}
protected:
std::vector<FlagInfo*>* myFlagInfos;
const KDTreePartition<E, N, V>* myPartition;
EdgeInfoComparator myComparator;
const std::shared_ptr<const LookupTable> myLookupTable;
double myMaxSpeed;
const SUMOTime myWeightPeriod;
SUMOTime myValidUntil;
AFBuilder<E, N, V, M>* myBuilder;
const std::string myType;
long long int myQueryVisits;
long long int myNumQueries;
long long int myQueryStartTime;
long long int myQueryTimeSum;
#ifdef AFRO_DEBUG_LEVEL_2
long long int myFlagContextStartTime;
long long int myFlagContextTimeSum;
#endif
private:
const Cell* myLastSettledEdgeCell;
std::tuple<int, int, bool> myLastFlagContext;
const Cell* myTargetEdgeCellLevel0;
};
template<class E, class N, class V, class M>
std::vector<bool>& AFRouter<E, N, V, M>::flags(const E* edge) {
assert(edge);
if (!myFlagInfos) {
throw std::runtime_error("flag infos not initialized, call compute() at least once before calling flags().");
}
return ((*myFlagInfos)[edge->getNumericalID()])->arcFlags;
}
template<class E, class N, class V, class M>
void AFRouter<E, N, V, M>::init(const int edgeID, const SUMOTime msTime) {
myTargetEdgeCellLevel0 = nullptr;
for (auto& edgeInfo : this->myFrontierList) {
edgeInfo->reset();
}
this->myFrontierList.clear();
for (auto& edgeInfo : this->myFound) {
edgeInfo->reset();
}
this->myFound.clear();
if (edgeID > -1) {
auto& fromInfo = this->myEdgeInfos[edgeID];
fromInfo.heuristicEffort = 0.;
fromInfo.effort = 0.;
fromInfo.leaveTime = STEPS2TIME(msTime);
fromInfo.prev = nullptr;
this->myFrontierList.push_back(&fromInfo);
}
}
template<class E, class N, class V, class M>
std::tuple<int, int, bool> AFRouter<E, N, V, M>::flagContextNaive(const E* settledEdge, const E* targetEdge) {
assert(settledEdge != nullptr && targetEdge != nullptr);
int sHARCLevel;
for (sHARCLevel = 0; sHARCLevel < myPartition->getNumberOfLevels() - 1; sHARCLevel++) {
int partitionLevel = sHARCLevel2PartitionLevel(sHARCLevel, myPartition->getNumberOfLevels());
const std::vector<const Cell*>& levelCells = myPartition->getCellsAtLevel(partitionLevel);
typename std::vector<const Cell*>::const_iterator first = levelCells.begin();
typename std::vector<const Cell*>::const_iterator last = levelCells.end();
typename std::vector<const Cell*>::const_iterator iter;
const Cell* settledEdgeCell = nullptr;
const Cell* targetEdgeCell = nullptr;
for (iter = first; iter != last; iter++) {
if (!settledEdgeCell && (*iter)->contains(settledEdge->getFromJunction())) {
settledEdgeCell = *iter;
}
if (!targetEdgeCell && (*iter)->contains(targetEdge->getFromJunction())) {
targetEdgeCell = *iter;
}
if (settledEdgeCell && targetEdgeCell) {
break;
}
}
assert(settledEdgeCell && targetEdgeCell);
if (settledEdgeCell->getSupercell() == targetEdgeCell->getSupercell()) {
return std::make_tuple(sHARCLevel, targetEdgeCell->isLeftOrLowerCell() ? 0 : 1,
settledEdgeCell == targetEdgeCell);
}
}
throw std::runtime_error("flagContext: relevant level could not be determined.");
}
template<class E, class N, class V, class M>
std::tuple<int, int, bool> AFRouter<E, N, V, M>::flagContext(const E* settledEdge, const E* targetEdge) {
assert(settledEdge != nullptr && targetEdge != nullptr);
int sHARCLevel = 0;
const Cell* settledEdgeCell = nullptr;
const Cell* targetEdgeCell = nullptr;
if (myLastSettledEdgeCell
&& myLastSettledEdgeCell->contains(settledEdge->getFromJunction())) {
return myLastFlagContext;
}
int numberOfPartitionLevels = myPartition->getNumberOfLevels();
if (numberOfPartitionLevels <= 4) {
int partitionLevel = sHARCLevel2PartitionLevel(sHARCLevel, myPartition->getNumberOfLevels());
const std::vector<const Cell*>& levelCells = myPartition->getCellsAtLevel(partitionLevel);
typename std::vector<const Cell*>::const_iterator first = levelCells.begin();
typename std::vector<const Cell*>::const_iterator last = levelCells.end();
typename std::vector<const Cell*>::const_iterator iter;
for (iter = first; iter != last; iter++) {
if (!settledEdgeCell
&& (*iter)->contains(settledEdge->getFromJunction())) {
settledEdgeCell = *iter;
}
if (!targetEdgeCell && myTargetEdgeCellLevel0) {
targetEdgeCell = myTargetEdgeCellLevel0;
} else if (!targetEdgeCell
&& (*iter)->contains(targetEdge->getFromJunction())) {
myTargetEdgeCellLevel0 = *iter;
targetEdgeCell = myTargetEdgeCellLevel0;
}
if (settledEdgeCell && targetEdgeCell) {
assert(myTargetEdgeCellLevel0);
break;
}
}
} else {
settledEdgeCell = myPartition->searchNode(settledEdge->getFromJunction());
if (!targetEdgeCell && myTargetEdgeCellLevel0) {
targetEdgeCell = myTargetEdgeCellLevel0;
} else if (!targetEdgeCell) {
myTargetEdgeCellLevel0 = myPartition->searchNode(targetEdge->getFromJunction());
targetEdgeCell = myTargetEdgeCellLevel0;
}
}
assert(settledEdgeCell && targetEdgeCell);
while (settledEdgeCell->getSupercell() != targetEdgeCell->getSupercell()) {
settledEdgeCell = settledEdgeCell->getSupercell();
targetEdgeCell = targetEdgeCell->getSupercell();
sHARCLevel++;
}
myLastSettledEdgeCell = settledEdgeCell;
std::tuple<int, int, bool> flagContext = std::make_tuple(sHARCLevel, targetEdgeCell->isLeftOrLowerCell() ? 0 : 1,
settledEdgeCell == targetEdgeCell);
myLastFlagContext = flagContext;
return flagContext;
}
template<class E, class N, class V, class M>
void AFRouter<E, N, V, M>::startQuery() {
myNumQueries++;
myQueryStartTime = SysUtils::getCurrentMillis();
SUMOAbstractRouter<E, V>::startQuery();
}
template<class E, class N, class V, class M>
void AFRouter<E, N, V, M>::endQuery(int visits) {
myQueryVisits += visits;
myQueryTimeSum += (SysUtils::getCurrentMillis() - myQueryStartTime);
SUMOAbstractRouter<E, V>::endQuery(visits);
}
template<class E, class N, class V, class M>
void AFRouter<E, N, V, M>::reportStatistics() {
if (myNumQueries > 0) {
WRITE_MESSAGE(myType + " answered " + toString(myNumQueries) + " queries and explored " + toString((double)myQueryVisits / (double)myNumQueries) + " edges on average.");
WRITE_MESSAGE(myType + " spent " + elapsedMs2string(myQueryTimeSum) + " answering queries (" + toString((double)myQueryTimeSum / (double)myNumQueries) + " ms on average).");
#ifdef AFRO_DEBUG_LEVEL_2
WRITE_MESSAGE("flagContext spent " + elapsedMs2string(myFlagContextTimeSum) + " (" + toString((double)myFlagContextTimeSum / (double)myNumQueries) + " ms on average).");
#endif
}
}
template<class E, class N, class V, class M>
void AFRouter<E, N, V, M>::resetStatistics() {
myNumQueries = 0;
myQueryVisits = 0;
myQueryTimeSum = 0;
myQueryStartTime = 0;
}