#include <config.h>
#include <set>
#include <string>
#include <utils/common/FileHelpers.h>
#include <utils/xml/XMLSubSys.h>
#include <utils/common/UtilExceptions.h>
#include <utils/common/MsgHandler.h>
#include <utils/common/StringUtils.h>
#include <utils/common/ToString.h>
#include <utils/options/OptionsCont.h>
#include <utils/xml/SUMOXMLDefinitions.h>
#include <utils/vehicle/SUMOVehicleParserHelper.h>
#include <router/RONet.h>
#include "ROJTREdge.h"
#include "ROJTRTurnDefLoader.h"
ROJTRTurnDefLoader::ROJTRTurnDefLoader(RONet& net) :
SUMOSAXHandler("turn-ratio-file"), myNet(net),
myIntervalBegin(0), myIntervalEnd(STEPS2TIME(SUMOTime_MAX)),
myEdge(nullptr),
mySourcesAreSinks(OptionsCont::getOptions().getBool("sources-are-sinks")),
myDiscountSources(OptionsCont::getOptions().getBool("discount-sources")),
myHaveWarnedAboutDeprecatedFormat(false)
{}
ROJTRTurnDefLoader::~ROJTRTurnDefLoader() {}
void
ROJTRTurnDefLoader::myStartElement(int element,
const SUMOSAXAttributes& attrs) {
bool ok = true;
switch (element) {
case SUMO_TAG_INTERVAL:
myIntervalBegin = attrs.get<double>(SUMO_ATTR_BEGIN, nullptr, ok);
myIntervalEnd = attrs.get<double>(SUMO_ATTR_END, nullptr, ok);
break;
case SUMO_TAG_FROMEDGE:
if (!myHaveWarnedAboutDeprecatedFormat) {
myHaveWarnedAboutDeprecatedFormat = true;
WRITE_WARNINGF(TL("The turn-file format with elements %, % is deprecated, please use % instead."),
toString(SUMO_TAG_FROMEDGE), toString(SUMO_TAG_TOEDGE), toString(SUMO_TAG_EDGEREL));
}
beginFromEdge(attrs);
break;
case SUMO_TAG_TOEDGE:
addToEdge(attrs);
break;
case SUMO_TAG_EDGEREL:
addEdgeRel(attrs);
break;
case SUMO_TAG_SINK:
if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
std::string edges = attrs.get<std::string>(SUMO_ATTR_EDGES, nullptr, ok);
StringTokenizer st(edges, StringTokenizer::WHITECHARS);
while (st.hasNext()) {
std::string id = st.next();
ROEdge* edge = myNet.getEdge(id);
if (edge == nullptr) {
throw ProcessError(TLF("The edge '%' declared as a sink is not known.", id));
}
edge->setSink();
}
}
break;
case SUMO_TAG_FLOW: {
const std::string flowID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
if (attrs.hasAttribute(SUMO_ATTR_FROM)) {
const std::string edgeID = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
ROEdge* edge = myNet.getEdge(edgeID);
if (edge == nullptr) {
throw ProcessError(TLF("The from-edge '%' in flow '%' is not known.", edgeID, flowID));
}
if (mySourcesAreSinks) {
edge->setSink();
}
if (myDiscountSources) {
SUMOVehicleParameter* pars = SUMOVehicleParserHelper::parseFlowAttributes(SUMO_TAG_FLOW, attrs, true, true, 0, TIME2STEPS(3600 * 24));
int numVehs = 0;
if (pars->repetitionProbability > 0) {
numVehs = int(STEPS2TIME(pars->repetitionEnd - pars->depart) * pars->repetitionProbability);
} else {
numVehs = pars->repetitionNumber;
}
delete pars;
static_cast<ROJTREdge*>(edge)->changeSourceFlow(numVehs);
}
} else {
WRITE_WARNINGF(TL("Ignoring flow '%' without 'from'"), flowID);
}
break;
}
case SUMO_TAG_SOURCE:
if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
std::string edges = attrs.get<std::string>(SUMO_ATTR_EDGES, nullptr, ok);
StringTokenizer st(edges, StringTokenizer::WHITECHARS);
while (st.hasNext()) {
std::string id = st.next();
ROEdge* edge = myNet.getEdge(id);
if (edge == nullptr) {
throw ProcessError(TLF("The edge '%' declared as a source is not known.", id));
}
edge->setSource();
}
}
break;
default:
break;
}
}
void
ROJTRTurnDefLoader::beginFromEdge(const SUMOSAXAttributes& attrs) {
myEdge = nullptr;
bool ok = true;
std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
if (!ok) {
return;
}
myEdge = static_cast<ROJTREdge*>(myNet.getEdge(id));
if (myEdge == nullptr) {
WRITE_ERRORF(TL("The edge '%' is not known within the network (within a 'from-edge' tag)."), id);
return;
}
}
void
ROJTRTurnDefLoader::addToEdge(const SUMOSAXAttributes& attrs) {
if (myEdge == nullptr) {
return;
}
bool ok = true;
std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
if (!ok) {
return;
}
ROJTREdge* edge = static_cast<ROJTREdge*>(myNet.getEdge(id));
if (edge == nullptr) {
WRITE_ERRORF(TL("The edge '%' is not known within the network (within a 'to-edge' tag)."), id);
return;
}
const double probability = attrs.get<double>(SUMO_ATTR_PROB, id.c_str(), ok);
if (ok) {
if (probability < 0) {
WRITE_ERRORF(TL("'probability' must be positive (in definition of to-edge '%')."), id);
} else {
myEdge->addFollowerProbability(edge, myIntervalBegin, myIntervalEnd, probability);
}
}
}
void
ROJTRTurnDefLoader::addEdgeRel(const SUMOSAXAttributes& attrs) {
bool ok = true;
std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
double probability = attrs.get<double>(
attrs.hasAttribute(SUMO_ATTR_COUNT) && !attrs.hasAttribute(SUMO_ATTR_PROB) ? SUMO_ATTR_COUNT : SUMO_ATTR_PROB,
(fromID + "->" + toID).c_str(), ok);
if (!ok) {
return;
}
ROJTREdge* from = static_cast<ROJTREdge*>(myNet.getEdge(fromID));
if (from == nullptr) {
WRITE_ERRORF(TL("The edge '%' is not known."), fromID);
return;
}
ROJTREdge* to = static_cast<ROJTREdge*>(myNet.getEdge(toID));
if (to == nullptr) {
WRITE_ERRORF(TL("The edge '%' is not known."), toID);
return;
}
if (probability < 0) {
WRITE_ERRORF(TL("'probability' must be positive (in edgeRelation from '%' to '%'."), fromID, toID);
} else {
from->addFollowerProbability(to, myIntervalBegin, myIntervalEnd, probability);
}
}