#pragma once
#include <config.h>
#include <vector>
#include <cassert>
#include "AFBuild.h"
#include "FlippedEdge.h"
#ifdef AFBL_DEBUG_LEVEL_2
#define AFBL_DEBUG_LEVEL_1
#endif
#ifdef AFBL_DEBUG_LEVEL_1
#define AFBL_DEBUG_LEVEL_0
#endif
template<class E, class N, class V, class M>
class AFBuilder {
public:
typedef typename AFInfo<E>::FlagInfo FlagInfo;
typedef AbstractLookupTable<FlippedEdge<E, N, V>, V> FlippedLookupTable;
AFBuilder(int numberOfLevels, const std::vector<E*>& edges, bool unbuildIsWarning,
typename SUMOAbstractRouter<FlippedEdge<E, N, V>, V>::Operation flippedOperation,
const std::shared_ptr<const FlippedLookupTable> flippedLookup = nullptr,
const bool havePermissions = false, const bool haveRestrictions = false,
const std::map<const FlippedEdge<E, N, V>*, double>* toProhibit = nullptr) :
myEdges(edges),
myNumberOfLevels(numberOfLevels),
myNumberOfArcFlags(2 * (myNumberOfLevels - 1)),
#ifdef AFBL_DEBUG_LEVEL_0
myArcFlagsFileName("arcflags.csv"),
#endif
myAmClean(true) {
for (const E* const edge : edges) {
myFlagInfos.push_back(new FlagInfo(edge));
}
#ifdef AFBL_DEBUG_LEVEL_0
std::cout << "Building flipped edges (" << edges.size() << " edges) / nodes..." << std::endl;
#endif
for (const E* const edge : edges) {
myFlippedEdges.push_back(edge->getFlippedRoutingEdge());
}
for (FlippedEdge<E, N, V>* flippedEdge : myFlippedEdges) {
flippedEdge->init();
}
#ifdef AFBL_DEBUG_LEVEL_0
std::cout << "Flipped edges / nodes are ready." << std::endl;
#endif
myFlippedPartition = new KDTreePartition<FlippedEdge<E, N, V>, FlippedNode<E, N, V>, V>(myNumberOfLevels,
myFlippedEdges, havePermissions, haveRestrictions);
#ifdef AFBL_DEBUG_LEVEL_0
std::cout << "Instantiating arc flag build..." << std::endl;
#endif
myArcFlagBuild = new AFBuild<E, N, V, M>(myFlippedEdges, myFlippedPartition, numberOfLevels, unbuildIsWarning,
flippedOperation, flippedLookup, havePermissions, haveRestrictions, toProhibit);
#ifdef AFBL_DEBUG_LEVEL_0
std::cout << "Arc flag build is instantiated (but still uninitialized)." << std::endl;
#endif
}
~AFBuilder();
AFBuild<E, N, V, M>* getArcFlagBuild() {
return myArcFlagBuild;
}
const std::vector<E*>& getEdges() {
return myEdges;
}
void reset();
std::vector<FlagInfo*>& build(SUMOTime msTime, const V* const vehicle);
int sHARCLevel2PartitionLevel(int sHARCLevel) {
return AFRouter<E, N, V, M>::sHARCLevel2PartitionLevel(sHARCLevel, myNumberOfLevels);
}
protected:
#ifdef AFBL_DEBUG_LEVEL_0
void loadFlagsFromCsv(const std::string fileName);
void saveFlagsToCsv(const std::string fileName);
bool fileExists(const std::string& name) {
std::ifstream f(name.c_str());
return f.good();
}
#endif
const std::vector<E*>& myEdges;
std::vector<FlippedEdge<E, N, V>*> myFlippedEdges;
KDTreePartition<FlippedEdge<E, N, V>, FlippedNode<E, N, V>, V>* myFlippedPartition;
std::vector<FlagInfo*> myFlagInfos;
AFBuild<E, N, V, M>* myArcFlagBuild;
int myNumberOfLevels;
int myNumberOfArcFlags;
#ifdef AFBL_DEBUG_LEVEL_0
const std::string myArcFlagsFileName;
#endif
bool myAmClean;
};
template<class E, class N, class V, class M>
AFBuilder<E, N, V, M>::~AFBuilder() {
delete myArcFlagBuild;
delete myFlippedPartition;
for (FlagInfo* flagInfo : myFlagInfos) {
delete flagInfo;
}
}
template<class E, class N, class V, class M>
void AFBuilder<E, N, V, M>::reset() {
for (FlagInfo* flagInfo : myFlagInfos) {
flagInfo->reset();
}
myAmClean = true;
}
template<class E, class N, class V, class M>
std::vector<typename AFInfo<E>::FlagInfo*>& AFBuilder<E, N, V, M>::build(SUMOTime msTime, const V* const vehicle) {
if (!myAmClean) {
reset();
}
assert(myFlippedPartition);
if (myFlippedPartition->isClean()) {
myFlippedPartition->init(vehicle);
myArcFlagBuild->setFlippedPartition(myFlippedPartition);
} else {
myFlippedPartition->reset(vehicle);
}
assert(myArcFlagBuild);
#ifdef AFBL_DEBUG_LEVEL_0
bool fileExists = this->fileExists(myArcFlagsFileName);
if (fileExists && myAmClean) {
std::cout << "Loading arc flags from file " << myArcFlagsFileName << std::endl;
loadFlagsFromCsv(myArcFlagsFileName);
std::cout << "Arc flags loaded." << std::endl;
} else {
#endif
myArcFlagBuild->init(msTime, vehicle, myFlagInfos);
#ifdef AFBL_DEBUG_LEVEL_0
}
#endif
delete myFlippedPartition;
myFlippedPartition = nullptr;
#ifdef AFBL_DEBUG_LEVEL_0
if (!fileExists) {
std::cout << "Saving arc flags..." << std::endl;
saveFlagsToCsv(myArcFlagsFileName);
std::cout << "Arc flags have been saved." << std::endl;
}
#endif
myAmClean = false;
return myFlagInfos;
}
#ifdef AFBL_DEBUG_LEVEL_0
template<class E, class N, class V, class M>
void AFBuilder<E, N, V, M>::saveFlagsToCsv(const std::string fileName) {
std::ofstream csvFile(fileName);
for (FlagInfo* flagInfo : myFlagInfos) {
if ((flagInfo->arcFlags).empty()) {
std::fill_n(std::back_inserter(flagInfo->arcFlags),
myNumberOfArcFlags, false);
}
for (bool flag : flagInfo->arcFlags) {
csvFile << flag;
}
csvFile << std::endl;
}
csvFile.close();
}
template<class E, class N, class V, class M>
void AFBuilder<E, N, V, M>::loadFlagsFromCsv(const std::string fileName) {
assert(myAmClean);
std::string fileNameCopy = fileName;
std::ifstream csvFile(fileNameCopy);
std::string result;
if (!csvFile.is_open()) {
result = fileNameCopy.insert(0, "Could not open CSV file ");
throw std::runtime_error(result);
}
for (FlagInfo* flagInfo : myFlagInfos) {
(flagInfo->arcFlags).clear();
std::fill_n(std::back_inserter(flagInfo->arcFlags),
myNumberOfArcFlags, false);
std::string line;
if (std::getline(csvFile, line)) {
if (line.empty()) {
continue;
}
std::stringstream stringStream(line);
std::string flagAsString(1, '\0');
int pos = 0;
while (stringStream.read(&flagAsString[0], 1)) {
(flagInfo->arcFlags)[pos++] = (!flagAsString.compare("0") ? 0 : 1);
}
} else {
result = fileNameCopy.insert(0, "CSV file ");
throw std::runtime_error(result.append(" has not enough lines - wrong or corrupted file?"));
}
}
myAmClean = false;
csvFile.close();
}
#endif