#include <config.h>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <iterator>
#include <mesosim/MELoop.h>
#include <microsim/MSGlobals.h>
#include <microsim/MSLane.h>
#include <microsim/MSEdge.h>
#include <microsim/MSEdgeControl.h>
#include <utils/common/StringTokenizer.h>
#include <utils/common/UtilExceptions.h>
#include <utils/options/OptionsCont.h>
#include "NLBuilder.h"
#include "NLEdgeControlBuilder.h"
#include <utils/iodevices/OutputDevice.h>
NLEdgeControlBuilder::NLEdgeControlBuilder()
: myCurrentNumericalLaneID(0), myCurrentNumericalEdgeID(0), myEdges(0), myCurrentLaneIndex(-1) {
myActiveEdge = (MSEdge*) nullptr;
myLaneStorage = new std::vector<MSLane*>();
}
NLEdgeControlBuilder::~NLEdgeControlBuilder() {
delete myLaneStorage;
}
void
NLEdgeControlBuilder::beginEdgeParsing(
const std::string& id, const SumoXMLEdgeFunc function,
const std::string& streetName,
const std::string& edgeType,
int priority,
const std::string& bidi,
double distance) {
myLaneStorage->clear();
myActiveEdge = buildEdge(id, function, streetName, edgeType, priority, distance);
if (MSEdge::dictionary(id) != nullptr) {
throw InvalidArgument("Another edge with the id '" + id + "' exists.");
}
myEdges.push_back(myActiveEdge);
if (bidi != "") {
myBidiEdges[myActiveEdge] = bidi;
}
}
MSLane*
NLEdgeControlBuilder::addLane(const std::string& id,
double maxSpeed, double friction, double length,
const PositionVector& shape, double width,
SVCPermissions permissions,
SVCPermissions changeLeft, SVCPermissions changeRight,
int index, bool isRampAccel,
const std::string& type,
const PositionVector& outlineShape) {
MSLane* lane = new MSLane(id, maxSpeed, friction, length, myActiveEdge, myCurrentNumericalLaneID++, shape, width, permissions, changeLeft, changeRight, index, isRampAccel, type, outlineShape);
myLaneStorage->push_back(lane);
myCurrentLaneIndex = index;
return lane;
}
void
NLEdgeControlBuilder::addStopOffsets(const StopOffset& stopOffset) {
if (myCurrentLaneIndex == -1) {
setDefaultStopOffset(stopOffset);
} else {
updateCurrentLaneStopOffset(stopOffset);
}
}
std::string
NLEdgeControlBuilder::reportCurrentEdgeOrLane() const {
std::stringstream ss;
if (myCurrentLaneIndex != -1) {
ss << "lane " << myCurrentLaneIndex << " of ";
}
ss << "edge '" << myActiveEdge->getID() << "'";
return ss.str();
}
void
NLEdgeControlBuilder::updateCurrentLaneStopOffset(const StopOffset& stopOffset) {
if (myLaneStorage->size() == 0) {
throw ProcessError("myLaneStorage cannot be empty");
}
if (stopOffset.isDefined()) {
if (myLaneStorage->back()->getLaneStopOffsets().isDefined()) {
WRITE_WARNING("Duplicate stopOffset definition for lane " + toString(myLaneStorage->back()->getIndex()) +
" on edge " + myActiveEdge->getID() + "!")
} else {
myLaneStorage->back()->setLaneStopOffset(stopOffset);
}
}
}
void
NLEdgeControlBuilder::setDefaultStopOffset(const StopOffset& stopOffsets) {
if (myCurrentDefaultStopOffset.isDefined()) {
WRITE_WARNING("Duplicate stopOffset definition for edge " + myActiveEdge->getID() + ". Ignoring duplicate specification.")
} else {
myCurrentDefaultStopOffset = stopOffsets;
}
}
void
NLEdgeControlBuilder::applyDefaultStopOffsetsToLanes() {
if (myActiveEdge == nullptr) {
throw ProcessError("myActiveEdge cannot be nullptr");
}
if (myCurrentDefaultStopOffset.isDefined()) {
for (const auto& l : *myLaneStorage) {
if (!l->getLaneStopOffsets().isDefined()) {
l->setLaneStopOffset(myCurrentDefaultStopOffset);
}
}
}
}
void
NLEdgeControlBuilder::addNeigh(const std::string id) {
myOppositeLanes.push_back({myLaneStorage->back(), id});
}
MSEdge*
NLEdgeControlBuilder::closeEdge() {
applyDefaultStopOffsetsToLanes();
std::vector<MSLane*>* lanes = new std::vector<MSLane*>();
lanes->reserve(myLaneStorage->size());
copy(myLaneStorage->begin(), myLaneStorage->end(), back_inserter(*lanes));
myLaneStorage->clear();
myActiveEdge->initialize(lanes);
myCurrentDefaultStopOffset.reset();
return myActiveEdge;
}
void
NLEdgeControlBuilder::closeLane() {
myCurrentLaneIndex = -1;
}
MSEdgeControl*
NLEdgeControlBuilder::build(const MMVersion& networkVersion) {
if (MSGlobals::gUseMesoSim && !OptionsCont::getOptions().getBool("meso-lane-queue")) {
MSEdge::setMesoIgnoredVClasses(parseVehicleClasses(OptionsCont::getOptions().getStringVector("meso-ignore-lanes-by-vclass")));
}
for (auto item : myOppositeLanes) {
MSLane* oppo = MSLane::dictionary(item.second);
if (oppo == nullptr) {
WRITE_ERRORF("Unknown neigh lane '%' for lane '%'", item.second, item.first->getID());
} else {
item.first->setOpposite(oppo);
}
}
std::set<const MSLane*> checked;
for (auto item : myOppositeLanes) {
if (item.first->getOpposite() != nullptr) {
if (item.first->getOpposite()->getOpposite() != item.first) {
if (checked.count(item.first->getOpposite()) == 0) {
WRITE_WARNINGF(TL("Asymmetrical neigh lane '%' for lane '%'"), item.second, item.first->getID());
item.first->getOpposite()->setOpposite(item.first);
} else {
throw ProcessError(TLF("Mutually inconsistent neigh lane definitions for lanes '%', '%' and '%'",
item.first->getID(), item.first->getOpposite()->getID(), Named::getIDSecure(item.first->getOpposite()->getOpposite())));
}
}
checked.insert(item.first);
checked.insert(item.first->getOpposite());
}
}
for (MSEdge* const edge : myEdges) {
edge->closeBuilding();
}
for (MSEdge* const edge : myEdges) {
edge->rebuildAllowedTargets(false);
if (MSGlobals::gUseMesoSim && !edge->getLanes().empty()) {
MSGlobals::gMesoNet->buildSegmentsFor(*edge, OptionsCont::getOptions());
}
}
if (MSGlobals::gUsingInternalLanes) {
for (MSEdge* const edge : myEdges) {
if (edge->isInternal()) {
if (edge->getNumSuccessors() != 1 || edge->getNumPredecessors() != 1) {
throw ProcessError(TLF("Internal edge '%' is not properly connected (probably a manually modified net.xml).", edge->getID()));
}
if (edge->getSuccessors()[0]->isRoundabout() || edge->getPredecessors()[0]->isRoundabout()) {
edge->markAsRoundabout();
}
}
}
}
if (!deprecatedVehicleClassesSeen.empty()) {
WRITE_WARNINGF(TL("Deprecated vehicle classes '%' in input network."), toString(deprecatedVehicleClassesSeen));
deprecatedVehicleClassesSeen.clear();
}
if (myBidiEdges.size() > 0 || networkVersion > MMVersion(1, 0)) {
for (auto& item : myBidiEdges) {
item.first->checkAndRegisterBiDirEdge(item.second);
}
} else {
for (MSEdge* e : myEdges) {
e->checkAndRegisterBiDirEdge();
}
}
for (MSEdge* const edge : myEdges) {
edge->buildLaneChanger();
}
return new MSEdgeControl(myEdges);
}
MSEdge*
NLEdgeControlBuilder::buildEdge(const std::string& id, const SumoXMLEdgeFunc function,
const std::string& streetName, const std::string& edgeType, const int priority, const double distance) {
return new MSEdge(id, myCurrentNumericalEdgeID++, function, streetName, edgeType, priority, distance);
}
void NLEdgeControlBuilder::addCrossingEdges(const std::vector<std::string>& crossingEdges) {
myActiveEdge->setCrossingEdges(crossingEdges);
}