#include <config.h>
#include <algorithm>
#include <utils/router/RouteCostCalculator.h>
#include <utils/vehicle/SUMOVTypeParameter.h>
#include <utils/router/SUMOAbstractRouter.h>
#include <utils/options/OptionsCont.h>
#include <utils/common/UtilExceptions.h>
#include <utils/common/ToString.h>
#include <utils/common/StringUtils.h>
#include <utils/common/RandHelper.h>
#include <utils/common/SUMOVehicleClass.h>
#include <utils/iodevices/OutputDevice.h>
#include "ROEdge.h"
#include "ROLane.h"
#include "RONode.h"
#include "ROPerson.h"
#include "RORoute.h"
#include "RORouteDef.h"
#include "ROVehicle.h"
#include "ROAbstractEdgeBuilder.h"
#include "RONet.h"
RONet* RONet::myInstance = nullptr;
RONet*
RONet::getInstance(void) {
if (myInstance != nullptr) {
return myInstance;
}
throw ProcessError(TL("A network was not yet constructed."));
}
RONet::RONet() :
myVehicleTypes(), myDefaultVTypeMayBeDeleted(true),
myDefaultPedTypeMayBeDeleted(true),
myDefaultBikeTypeMayBeDeleted(true),
myDefaultTaxiTypeMayBeDeleted(true),
myDefaultRailTypeMayBeDeleted(true),
myHaveActiveFlows(true),
myRoutesOutput(nullptr), myRouteAlternativesOutput(nullptr), myTypesOutput(nullptr),
myReadRouteNo(0), myDiscardedRouteNo(0), myWrittenRouteNo(0),
myHavePermissions(false),
myNumInternalEdges(0),
myErrorHandler(OptionsCont::getOptions().exists("ignore-errors")
&& OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
myKeepVTypeDist(OptionsCont::getOptions().exists("keep-vtype-distributions")
&& OptionsCont::getOptions().getBool("keep-vtype-distributions")),
myDoPTRouting(!OptionsCont::getOptions().exists("ptline-routing")
|| OptionsCont::getOptions().getBool("ptline-routing")),
myHasBidiEdges(false) {
if (myInstance != nullptr) {
throw ProcessError(TL("A network was already constructed."));
}
SUMOVTypeParameter* type = new SUMOVTypeParameter(DEFAULT_VTYPE_ID, SVC_PASSENGER);
type->onlyReferenced = true;
myVehicleTypes.add(type->id, type);
SUMOVTypeParameter* defPedType = new SUMOVTypeParameter(DEFAULT_PEDTYPE_ID, SVC_PEDESTRIAN);
defPedType->onlyReferenced = true;
defPedType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
myVehicleTypes.add(defPedType->id, defPedType);
SUMOVTypeParameter* defBikeType = new SUMOVTypeParameter(DEFAULT_BIKETYPE_ID, SVC_BICYCLE);
defBikeType->onlyReferenced = true;
defBikeType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
myVehicleTypes.add(defBikeType->id, defBikeType);
SUMOVTypeParameter* defTaxiType = new SUMOVTypeParameter(DEFAULT_TAXITYPE_ID, SVC_TAXI);
defTaxiType->onlyReferenced = true;
defTaxiType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
myVehicleTypes.add(defTaxiType->id, defTaxiType);
SUMOVTypeParameter* defRailType = new SUMOVTypeParameter(DEFAULT_RAILTYPE_ID, SVC_RAIL);
defRailType->onlyReferenced = true;
defRailType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
myVehicleTypes.add(defRailType->id, defRailType);
myInstance = this;
}
RONet::~RONet() {
for (const auto& routables : myRoutables) {
for (RORoutable* const r : routables.second) {
const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
delete veh->getRouteDefinition();
}
}
delete r;
}
}
for (const RORoutable* const r : myPTVehicles) {
const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
delete veh->getRouteDefinition();
}
}
delete r;
}
myRoutables.clear();
for (const auto& vTypeDist : myVTypeDistDict) {
delete vTypeDist.second;
}
}
void
RONet::addRestriction(const std::string& id, const SUMOVehicleClass svc, const double speed) {
myRestrictions[id][svc] = speed;
}
const std::map<SUMOVehicleClass, double>*
RONet::getRestrictions(const std::string& id) const {
std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = myRestrictions.find(id);
if (i == myRestrictions.end()) {
return nullptr;
}
return &i->second;
}
bool
RONet::addEdge(ROEdge* edge) {
if (!myEdges.add(edge->getID(), edge)) {
WRITE_ERRORF(TL("The edge '%' occurs at least twice."), edge->getID());
delete edge;
return false;
}
if (edge->isInternal()) {
myNumInternalEdges += 1;
}
return true;
}
bool
RONet::addDistrict(const std::string id, ROEdge* source, ROEdge* sink) {
if (myDistricts.count(id) > 0) {
WRITE_ERRORF(TL("The TAZ '%' occurs at least twice."), id);
delete source;
delete sink;
return false;
}
sink->setFunction(SumoXMLEdgeFunc::CONNECTOR);
if (!addEdge(sink)) {
return false;
}
source->setFunction(SumoXMLEdgeFunc::CONNECTOR);
if (!addEdge(source)) {
return false;
}
sink->setOtherTazConnector(source);
source->setOtherTazConnector(sink);
myDistricts[id] = std::make_pair(std::vector<std::string>(), std::vector<std::string>());
return true;
}
bool
RONet::addDistrictEdge(const std::string tazID, const std::string edgeID, const bool isSource) {
if (myDistricts.count(tazID) == 0) {
WRITE_ERRORF(TL("The TAZ '%' is unknown."), tazID);
return false;
}
ROEdge* edge = getEdge(edgeID);
if (edge == nullptr) {
WRITE_ERRORF(TL("The edge '%' for TAZ '%' is unknown."), edgeID, tazID);
return false;
}
if (isSource) {
getEdge(tazID + "-source")->addSuccessor(edge);
myDistricts[tazID].first.push_back(edgeID);
} else {
edge->addSuccessor(getEdge(tazID + "-sink"));
myDistricts[tazID].second.push_back(edgeID);
}
return true;
}
void
RONet::addJunctionTaz(ROAbstractEdgeBuilder& eb) {
for (auto item : myNodes) {
const std::string tazID = item.first;
if (myDistricts.count(tazID) != 0) {
WRITE_WARNINGF(TL("A TAZ with id '%' already exists. Not building junction TAZ."), tazID);
continue;
}
const std::string sourceID = tazID + "-source";
const std::string sinkID = tazID + "-sink";
ROEdge* sink = eb.buildEdge(sinkID, nullptr, nullptr, 0, "");
ROEdge* source = eb.buildEdge(sourceID, nullptr, nullptr, 0, "");
sink->setOtherTazConnector(source);
source->setOtherTazConnector(sink);
if (!addDistrict(tazID, source, sink)) {
continue;
}
auto& district = myDistricts[tazID];
const RONode* junction = item.second;
for (const ROEdge* edge : junction->getIncoming()) {
if (!edge->isInternal()) {
const_cast<ROEdge*>(edge)->addSuccessor(sink);
district.second.push_back(edge->getID());
}
}
for (const ROEdge* edge : junction->getOutgoing()) {
if (!edge->isInternal()) {
source->addSuccessor(const_cast<ROEdge*>(edge));
district.first.push_back(edge->getID());
}
}
}
}
void
RONet::setBidiEdges(const std::map<ROEdge*, std::string>& bidiMap) {
for (const auto& item : bidiMap) {
ROEdge* bidi = myEdges.get(item.second);
if (bidi == nullptr) {
WRITE_ERRORF(TL("The bidi edge '%' is not known."), item.second);
}
item.first->setBidiEdge(bidi);
myHasBidiEdges = true;
}
}
void
RONet::addNode(RONode* node) {
if (!myNodes.add(node->getID(), node)) {
WRITE_ERRORF(TL("The node '%' occurs at least twice."), node->getID());
delete node;
}
}
void
RONet::addStoppingPlace(const std::string& id, const SumoXMLTag category, SUMOVehicleParameter::Stop* stop) {
if (!myStoppingPlaces[category == SUMO_TAG_TRAIN_STOP ? SUMO_TAG_BUS_STOP : category].add(id, stop)) {
WRITE_ERRORF(TL("The % '%' occurs at least twice."), toString(category), id);
delete stop;
}
}
bool
RONet::addRouteDef(RORouteDef* def) {
return myRoutes.add(def->getID(), def);
}
void
RONet::openOutput(const OptionsCont& options) {
if (options.isSet("output-file") && options.getString("output-file") != "") {
myRoutesOutput = &OutputDevice::getDevice(options.getString("output-file"));
if (myRoutesOutput->isNull()) {
myRoutesOutput = nullptr;
} else {
myRoutesOutput->writeXMLHeader("routes", "routes_file.xsd");
}
}
if (options.exists("alternatives-output") && options.isSet("alternatives-output")
&& !(options.exists("write-trips") && options.getBool("write-trips"))) {
myRouteAlternativesOutput = &OutputDevice::getDevice(options.getString("alternatives-output"));
if (myRouteAlternativesOutput->isNull()) {
myRouteAlternativesOutput = nullptr;
} else {
myRouteAlternativesOutput->writeXMLHeader("routes", "routes_file.xsd");
}
}
if (options.isSet("vtype-output")) {
myTypesOutput = &OutputDevice::getDevice(options.getString("vtype-output"));
myTypesOutput->writeXMLHeader("routes", "routes_file.xsd");
}
}
void
RONet::writeIntermodal(const OptionsCont& options, ROIntermodalRouter& router) const {
if (options.exists("intermodal-network-output") && options.isSet("intermodal-network-output")) {
OutputDevice::createDeviceByOption("intermodal-network-output", "intermodal");
router.writeNetwork(OutputDevice::getDevice(options.getString("intermodal-network-output")));
}
if (options.exists("intermodal-weight-output") && options.isSet("intermodal-weight-output")) {
OutputDevice::createDeviceByOption("intermodal-weight-output", "weights", "meandata_file.xsd");
OutputDevice& dev = OutputDevice::getDeviceByOption("intermodal-weight-output");
dev.openTag(SUMO_TAG_INTERVAL);
dev.writeAttr(SUMO_ATTR_ID, "intermodalweights");
dev.writeAttr(SUMO_ATTR_BEGIN, 0);
dev.writeAttr(SUMO_ATTR_END, SUMOTime_MAX);
router.writeWeights(dev);
dev.closeTag();
}
}
void
RONet::cleanup() {
if (myRoutesOutput != nullptr) {
myRoutesOutput->close();
}
if (myRouteAlternativesOutput != nullptr) {
myRouteAlternativesOutput->close();
}
if (myTypesOutput != nullptr) {
myTypesOutput->close();
}
RouteCostCalculator<RORoute, ROEdge, ROVehicle>::cleanup();
#ifdef HAVE_FOX
if (myThreadPool.size() > 0) {
myThreadPool.clear();
}
#endif
}
SUMOVTypeParameter*
RONet::getVehicleTypeSecure(const std::string& id) {
SUMOVTypeParameter* type = myVehicleTypes.get(id);
if (id == DEFAULT_VTYPE_ID) {
myDefaultVTypeMayBeDeleted = false;
} else if (id == DEFAULT_PEDTYPE_ID) {
myDefaultPedTypeMayBeDeleted = false;
} else if (id == DEFAULT_BIKETYPE_ID) {
myDefaultBikeTypeMayBeDeleted = false;
} else if (id == DEFAULT_TAXITYPE_ID) {
myDefaultTaxiTypeMayBeDeleted = false;
} else if (id == DEFAULT_RAILTYPE_ID) {
myDefaultRailTypeMayBeDeleted = false;
}
if (type != nullptr) {
return type;
}
VTypeDistDictType::iterator it2 = myVTypeDistDict.find(id);
if (it2 != myVTypeDistDict.end()) {
return it2->second->get();
}
if (id == "") {
myDefaultVTypeMayBeDeleted = false;
return myVehicleTypes.get(DEFAULT_VTYPE_ID);
}
return type;
}
bool
RONet::checkVType(const std::string& id) {
if (id == DEFAULT_VTYPE_ID) {
if (myDefaultVTypeMayBeDeleted) {
myVehicleTypes.remove(id);
myDefaultVTypeMayBeDeleted = false;
} else {
return false;
}
} else if (id == DEFAULT_PEDTYPE_ID) {
if (myDefaultPedTypeMayBeDeleted) {
myVehicleTypes.remove(id);
myDefaultPedTypeMayBeDeleted = false;
} else {
return false;
}
} else if (id == DEFAULT_BIKETYPE_ID) {
if (myDefaultBikeTypeMayBeDeleted) {
myVehicleTypes.remove(id);
myDefaultBikeTypeMayBeDeleted = false;
} else {
return false;
}
} else if (id == DEFAULT_TAXITYPE_ID) {
if (myDefaultTaxiTypeMayBeDeleted) {
myVehicleTypes.remove(id);
myDefaultTaxiTypeMayBeDeleted = false;
} else {
return false;
}
} else if (id == DEFAULT_RAILTYPE_ID) {
if (myDefaultRailTypeMayBeDeleted) {
myVehicleTypes.remove(id);
myDefaultRailTypeMayBeDeleted = false;
} else {
return false;
}
} else {
if (myVehicleTypes.get(id) != 0 || myVTypeDistDict.find(id) != myVTypeDistDict.end()) {
return false;
}
}
return true;
}
bool
RONet::addVehicleType(SUMOVTypeParameter* type) {
if (checkVType(type->id)) {
myVehicleTypes.add(type->id, type);
} else {
WRITE_ERRORF(TL("The vehicle type '%' occurs at least twice."), type->id);
delete type;
return false;
}
return true;
}
bool
RONet::addVTypeDistribution(const std::string& id, RandomDistributor<SUMOVTypeParameter*>* vehTypeDistribution) {
if (checkVType(id)) {
myVTypeDistDict[id] = vehTypeDistribution;
return true;
}
delete vehTypeDistribution;
return false;
}
bool
RONet::addVehicle(const std::string& id, ROVehicle* veh) {
if (myVehIDs.find(id) == myVehIDs.end()) {
myVehIDs[id] = veh->getParameter().departProcedure == DepartDefinition::TRIGGERED ? -1 : veh->getDepartureTime();
if (veh->isPublicTransport()) {
if (!veh->isPartOfFlow()) {
myPTVehicles.push_back(veh);
}
if (!myDoPTRouting) {
return true;
}
}
myRoutables[veh->getDepart()].push_back(veh);
return true;
}
WRITE_ERRORF(TL("Another vehicle with the id '%' exists."), id);
delete veh;
return false;
}
bool
RONet::knowsVehicle(const std::string& id) const {
return myVehIDs.find(id) != myVehIDs.end();
}
SUMOTime
RONet::getDeparture(const std::string& vehID) const {
auto it = myVehIDs.find(vehID);
if (it != myVehIDs.end()) {
return it->second;
} else {
throw ProcessError(TLF("Requesting departure time for unknown vehicle '%'", vehID));
}
}
bool
RONet::addFlow(SUMOVehicleParameter* flow, const bool randomize) {
if (randomize && flow->repetitionOffset >= 0) {
myDepartures[flow->id].reserve(flow->repetitionNumber);
for (int i = 0; i < flow->repetitionNumber; ++i) {
myDepartures[flow->id].push_back(flow->depart + RandHelper::rand(flow->repetitionNumber * flow->repetitionOffset));
}
std::sort(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
std::reverse(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
}
const bool added = myFlows.add(flow->id, flow);
if (added) {
myHaveActiveFlows = true;
}
return added;
}
bool
RONet::addPerson(ROPerson* person) {
if (myPersonIDs.count(person->getID()) == 0) {
myPersonIDs.insert(person->getID());
myRoutables[person->getDepart()].push_back(person);
return true;
}
WRITE_ERRORF(TL("Another person with the id '%' exists."), person->getID());
return false;
}
void
RONet::addContainer(const SUMOTime depart, const std::string desc) {
myContainers.insert(std::pair<const SUMOTime, const std::string>(depart, desc));
}
void
RONet::checkFlows(SUMOTime time, MsgHandler* errorHandler) {
myHaveActiveFlows = false;
for (const auto& i : myFlows) {
SUMOVehicleParameter* const pars = i.second;
if (pars->line != "" && !myDoPTRouting) {
continue;
}
if (pars->repetitionProbability > 0) {
if (pars->repetitionEnd > pars->depart && pars->repetitionsDone < pars->repetitionNumber) {
myHaveActiveFlows = true;
}
const SUMOTime origDepart = pars->depart;
while (pars->depart < time && pars->repetitionsDone < pars->repetitionNumber) {
if (pars->repetitionEnd <= pars->depart) {
break;
}
if (RandHelper::rand() < (pars->repetitionProbability * TS)) {
SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
newPars->id = pars->id + "." + toString(pars->repetitionsDone);
newPars->depart = pars->depart;
for (StopParVector::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
if (stop->until >= 0) {
stop->until += pars->depart - origDepart;
}
}
pars->repetitionsDone++;
const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
if (type == nullptr) {
type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
} else if (!myKeepVTypeDist) {
newPars->vtypeid = type->id;
}
const SUMOTime stopOffset = pars->routeid[0] == '!' ? pars->depart - origDepart : pars->depart;
RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
addVehicle(newPars->id, veh);
delete newPars;
}
pars->depart += DELTA_T;
}
} else {
SUMOTime depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
while (pars->repetitionsDone < pars->repetitionNumber && pars->repetitionEnd >= depart) {
myHaveActiveFlows = true;
depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
if (myDepartures.find(pars->id) != myDepartures.end()) {
depart = myDepartures[pars->id].back();
}
if (depart >= time + DELTA_T) {
break;
}
if (myDepartures.find(pars->id) != myDepartures.end()) {
myDepartures[pars->id].pop_back();
}
SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
newPars->id = pars->id + "." + toString(pars->repetitionsDone);
newPars->depart = depart;
for (StopParVector::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
if (stop->until >= 0) {
stop->until += depart - pars->depart;
}
}
pars->incrementFlow(1);
const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
if (type == nullptr) {
type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
} else {
newPars->vtypeid = type->id;
}
const SUMOTime stopOffset = pars->routeid[0] == '!' ? depart - pars->depart : depart;
RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
addVehicle(newPars->id, veh);
delete newPars;
}
}
}
}
void
RONet::createBulkRouteRequests(const RORouterProvider& provider, const SUMOTime time, const bool removeLoops) {
std::map<const int, std::vector<RORoutable*> > bulkVehs;
for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
if (i->first >= time) {
break;
}
for (RORoutable* const routable : i->second) {
const ROEdge* const depEdge = routable->getDepartEdge();
bulkVehs[depEdge->getNumericalID()].push_back(routable);
RORoutable* const first = bulkVehs[depEdge->getNumericalID()].front();
if (first->getMaxSpeed() != routable->getMaxSpeed()) {
WRITE_WARNINGF(TL("Bulking different maximum speeds ('%' and '%') may lead to suboptimal routes."), first->getID(), routable->getID());
}
if (first->getVClass() != routable->getVClass()) {
WRITE_WARNINGF(TL("Bulking different vehicle classes ('%' and '%') may lead to invalid routes."), first->getID(), routable->getID());
}
}
}
#ifdef HAVE_FOX
int workerIndex = 0;
#endif
for (std::map<const int, std::vector<RORoutable*> >::const_iterator i = bulkVehs.begin(); i != bulkVehs.end(); ++i) {
#ifdef HAVE_FOX
if (myThreadPool.size() > 0) {
bool bulk = true;
for (RORoutable* const r : i->second) {
myThreadPool.add(new RoutingTask(r, removeLoops, myErrorHandler), workerIndex);
if (bulk) {
myThreadPool.add(new BulkmodeTask(true), workerIndex);
bulk = false;
}
}
myThreadPool.add(new BulkmodeTask(false), workerIndex);
workerIndex++;
if (workerIndex == (int)myThreadPool.size()) {
workerIndex = 0;
}
continue;
}
#endif
for (RORoutable* const r : i->second) {
r->computeRoute(provider, removeLoops, myErrorHandler);
provider.setBulkMode(true);
}
provider.setBulkMode(false);
}
}
SUMOTime
RONet::saveAndRemoveRoutesUntil(OptionsCont& options, const RORouterProvider& provider,
SUMOTime time) {
MsgHandler* mh = (options.getBool("ignore-errors") ?
MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance());
if (myHaveActiveFlows) {
checkFlows(time, mh);
}
SUMOTime lastTime = -1;
const bool removeLoops = options.getBool("remove-loops");
#ifdef HAVE_FOX
const int maxNumThreads = options.getInt("routing-threads");
#endif
if (myRoutables.size() != 0) {
if (options.getBool("bulk-routing")) {
#ifdef HAVE_FOX
while ((int)myThreadPool.size() < maxNumThreads) {
new WorkerThread(myThreadPool, provider);
}
#endif
createBulkRouteRequests(provider, time, removeLoops);
} else {
for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
if (i->first >= time) {
break;
}
for (RORoutable* const routable : i->second) {
#ifdef HAVE_FOX
if (maxNumThreads > 0) {
const int numThreads = (int)myThreadPool.size();
if (numThreads == 0) {
routable->computeRoute(provider, removeLoops, myErrorHandler);
new WorkerThread(myThreadPool, provider);
} else {
if (numThreads < maxNumThreads && myThreadPool.isFull()) {
new WorkerThread(myThreadPool, provider);
}
myThreadPool.add(new RoutingTask(routable, removeLoops, myErrorHandler));
}
continue;
}
#endif
routable->computeRoute(provider, removeLoops, myErrorHandler);
}
}
}
#ifdef HAVE_FOX
myThreadPool.waitAll();
#endif
}
const double scale = options.exists("scale-suffix") ? options.getFloat("scale") : 1;
while (myRoutables.size() != 0 || myContainers.size() != 0) {
RoutablesMap::iterator routables = myRoutables.begin();
const SUMOTime routableTime = routables == myRoutables.end() ? SUMOTime_MAX : routables->first;
ContainerMap::iterator container = myContainers.begin();
const SUMOTime containerTime = container == myContainers.end() ? SUMOTime_MAX : container->first;
if (routableTime >= time && containerTime >= time) {
lastTime = MIN2(routableTime, containerTime);
break;
}
const SUMOTime minTime = MIN2(routableTime, containerTime);
if (routableTime == minTime) {
if (lastTime != routableTime && lastTime != -1) {
if (options.getInt("stats-period") >= 0 && ((int)routableTime % options.getInt("stats-period")) == 0) {
WRITE_MESSAGE("Read: " + toString(myVehIDs.size()) + ", Discarded: " + toString(myDiscardedRouteNo) + ", Written: " + toString(myWrittenRouteNo));
}
}
lastTime = routableTime;
for (const RORoutable* const r : routables->second) {
if (r->getRoutingSuccess()) {
int quota = getScalingQuota(scale, myWrittenRouteNo);
r->write(myRoutesOutput, myRouteAlternativesOutput, myTypesOutput, options, quota);
myWrittenRouteNo++;
} else {
myDiscardedRouteNo++;
}
if (!r->isPublicTransport() || r->isPartOfFlow()) {
const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
if (r->isPartOfFlow() || !myRoutes.remove(veh->getRouteDefinition()->getID())) {
delete veh->getRouteDefinition();
}
}
delete r;
}
}
myRoutables.erase(routables);
}
if (containerTime == minTime) {
myRoutesOutput->writePreformattedTag(container->second);
if (myRouteAlternativesOutput != nullptr) {
myRouteAlternativesOutput->writePreformattedTag(container->second);
}
myContainers.erase(container);
}
}
return lastTime;
}
bool
RONet::furtherStored() {
return myRoutables.size() > 0 || (myFlows.size() > 0 && myHaveActiveFlows) || myContainers.size() > 0;
}
int
RONet::getEdgeNumber() const {
return myEdges.size();
}
int
RONet::getInternalEdgeNumber() const {
return myNumInternalEdges;
}
ROEdge*
RONet::getEdgeForLaneID(const std::string& laneID) const {
return getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(laneID));
}
ROLane*
RONet::getLane(const std::string& laneID) const {
int laneIndex = SUMOXMLDefinitions::getIndexFromLane(laneID);
return getEdgeForLaneID(laneID)->getLanes()[laneIndex];
}
void
RONet::adaptIntermodalRouter(ROIntermodalRouter& router) {
double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
for (const auto& stopType : myInstance->myStoppingPlaces) {
const SumoXMLTag element = stopType.first;
for (const auto& stop : stopType.second) {
router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(stop.second->lane),
stop.second->startPos, stop.second->endPos, 0., element, false, taxiWait);
if (element == SUMO_TAG_BUS_STOP) {
for (const auto& a : stop.second->accessPos) {
router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(std::get<0>(a)),
std::get<1>(a), std::get<1>(a), std::get<2>(a), SUMO_TAG_BUS_STOP, true, taxiWait);
}
}
}
}
for (const auto& i : myInstance->myFlows) {
if (i.second->line != "") {
const RORouteDef* const route = myInstance->getRouteDef(i.second->routeid);
const StopParVector* addStops = nullptr;
if (route != nullptr && route->getFirstRoute() != nullptr) {
addStops = &route->getFirstRoute()->getStops();
}
router.getNetwork()->addSchedule(*i.second, addStops);
}
}
for (const RORoutable* const veh : myInstance->myPTVehicles) {
router.getNetwork()->addSchedule(veh->getParameter());
}
if ((router.getCarWalkTransfer() & ModeChangeOptions::TAXI_PICKUP_ANYWHERE) != 0) {
for (const ROEdge* edge : ROEdge::getAllEdges()) {
if ((edge->getPermissions() & SVC_PEDESTRIAN) != 0 && (edge->getPermissions() & SVC_TAXI) != 0) {
router.getNetwork()->addCarAccess(edge, SVC_TAXI, taxiWait);
}
}
}
}
bool
RONet::hasPermissions() const {
return myHavePermissions;
}
void
RONet::setPermissionsFound() {
myHavePermissions = true;
}
bool
RONet::hasLoadedEffort() const {
for (const auto& item : myEdges) {
if (item.second->hasStoredEffort()) {
return true;
}
}
return false;
}
const std::string
RONet::getStoppingPlaceName(const std::string& id) const {
for (const auto& mapItem : myStoppingPlaces) {
SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
if (stop != nullptr) {
return stop->busstop;
}
}
return "";
}
const std::string
RONet::getStoppingPlaceElement(const std::string& id) const {
for (const auto& mapItem : myStoppingPlaces) {
SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
if (stop != nullptr) {
return stop->actType;
}
}
return toString(SUMO_TAG_BUS_STOP);
}
#ifdef HAVE_FOX
void
RONet::RoutingTask::run(MFXWorkerThread* context) {
myRoutable->computeRoute(*static_cast<WorkerThread*>(context), myRemoveLoops, myErrorHandler);
}
#endif