#include <netbuild/NBAlgorithms.h>
#include <netbuild/NBNetBuilder.h>
#include <netedit/GNETagProperties.h>
#include <netedit/dialogs/basic/GNEWarningBasicDialog.h>
#include <netedit/dialogs/basic/GNEQuestionBasicDialog.h>
#include <netedit/changes/GNEChange_Additional.h>
#include <netedit/changes/GNEChange_Attribute.h>
#include <netedit/changes/GNEChange_Connection.h>
#include <netedit/changes/GNEChange_Crossing.h>
#include <netedit/changes/GNEChange_DataInterval.h>
#include <netedit/changes/GNEChange_DataSet.h>
#include <netedit/changes/GNEChange_DemandElement.h>
#include <netedit/changes/GNEChange_Edge.h>
#include <netedit/changes/GNEChange_GenericData.h>
#include <netedit/changes/GNEChange_Junction.h>
#include <netedit/changes/GNEChange_Lane.h>
#include <netedit/changes/GNEChange_MeanData.h>
#include <netedit/changes/GNEChange_RegisterJoin.h>
#include <netedit/changes/GNEChange_TAZSourceSink.h>
#include <netedit/dialogs/fix/GNEFixAdditionalElementsDialog.h>
#include <netedit/dialogs/fix/GNEFixDemandElementsDialog.h>
#include <netedit/elements/GNEGeneralHandler.h>
#include <netedit/elements/data/GNEDataHandler.h>
#include <netedit/elements/data/GNEDataInterval.h>
#include <netedit/elements/data/GNEMeanData.h>
#include <netedit/elements/network/GNEConnection.h>
#include <netedit/elements/network/GNECrossing.h>
#include <netedit/elements/network/GNEEdgeTemplate.h>
#include <netedit/elements/network/GNEEdgeType.h>
#include <netedit/elements/network/GNELaneType.h>
#include <netedit/frames/common/GNEInspectorFrame.h>
#include <netwrite/NWFrame.h>
#include <netwrite/NWWriter_SUMO.h>
#include <netwrite/NWWriter_XML.h>
#include <utils/common/StringTokenizer.h>
#include <utils/gui/div/GLHelper.h>
#include <utils/gui/div/GUIDesigns.h>
#include <utils/gui/div/GUIParameterTableWindow.h>
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
#include <utils/gui/globjects/GUIGlObjectStorage.h>
#include "GNEApplicationWindow.h"
#include "GNENet.h"
#include "GNEUndoList.h"
#include "GNEViewParent.h"
FXIMPLEMENT_ABSTRACT(GNENetHelper::GNEChange_ReplaceEdgeInTLS, GNEChange, nullptr, 0)
const double GNENet::Z_INITIALIZED = 1;
const std::map<SumoXMLAttr, std::string> GNENet::EMPTY_HEADER;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4355)
#endif
GNENet::GNENet(NBNetBuilder* netBuilder, const GNETagPropertiesDatabase* tagPropertiesDatabase) :
GUIGlObject(GLO_NETWORK, "", nullptr),
myNetBuilder(netBuilder),
myTagPropertiesDatabase(tagPropertiesDatabase),
myAttributeCarriers(new GNENetHelper::AttributeCarriers(this)),
myACTemplates(new GNENetHelper::ACTemplate(this)),
mySavingFilesHandler(new GNENetHelper::SavingFilesHandler(this)),
mySavingStatus(new GNENetHelper::SavingStatus(this)),
myNetworkPathManager(new GNEPathManager(this)),
myDemandPathManager(new GNEPathManager(this)),
myDataPathManager(new GNEPathManager(this)) {
GUIGlObjectStorage::gIDStorage.setNetObject(this);
myACTemplates->buildTemplates();
initJunctionsAndEdges();
if (myZBoundary.ymin() != Z_INITIALIZED) {
myZBoundary.add(0, 0);
}
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
GNENet::~GNENet() {
delete myNetworkPathManager;
delete myDemandPathManager;
delete myDataPathManager;
delete myAttributeCarriers;
delete myACTemplates;
delete mySavingStatus;
delete myNetBuilder;
}
const GNETagPropertiesDatabase*
GNENet::getTagPropertiesDatabase() const {
return myTagPropertiesDatabase;
}
GNENetHelper::AttributeCarriers*
GNENet::getAttributeCarriers() const {
return myAttributeCarriers;
}
GNENetHelper::ACTemplate*
GNENet::getACTemplates() const {
return myACTemplates;
}
GNENetHelper::SavingFilesHandler*
GNENet::getSavingFilesHandler() const {
return mySavingFilesHandler;
}
GNENetHelper::SavingStatus*
GNENet::getSavingStatus() const {
return mySavingStatus;
}
GNEPathManager*
GNENet::getNetworkPathManager() {
return myNetworkPathManager;
}
GNEPathManager*
GNENet::getDemandPathManager() {
return myDemandPathManager;
}
GNEPathManager*
GNENet::getDataPathManager() {
return myDataPathManager;
}
const Boundary&
GNENet::getBoundary() const {
return myGrid;
}
SUMORTree&
GNENet::getGrid() {
return myGrid;
}
const std::map<std::string, int>&
GNENet::getEdgesAndNumberOfLanes() const {
return myEdgesAndNumberOfLanes;
}
GUIGLObjectPopupMenu*
GNENet::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
buildPopupHeader(ret, app);
buildCenterPopupEntry(ret);
buildPositionCopyEntry(ret, app);
if (GeoConvHelper::getFinal().usingGeoProjection()) {
GUIDesigns::buildFXMenuCommand(ret, TL("Copy view geo-boundary to clipboard"), nullptr, ret, MID_COPY_VIEW_GEOBOUNDARY);
}
return ret;
}
GUIParameterTableWindow*
GNENet::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
ret->closeBuilding();
return ret;
}
void
GNENet::drawGL(const GUIVisualizationSettings& s) const {
GLHelper::drawBoundary(s, getCenteringBoundary());
}
Boundary
GNENet::getCenteringBoundary() const {
return getBoundary();
}
void
GNENet::expandBoundary(const Boundary& newBoundary) {
myGrid.add(newBoundary);
}
const Boundary&
GNENet::getZBoundary() const {
return myZBoundary;
}
void
GNENet::addZValueInBoundary(const double z) {
if (z != 0) {
myZBoundary.add(z, Z_INITIALIZED);
}
}
GNEJunction*
GNENet::createJunction(const Position& pos, GNEUndoList* undoList) {
const std::string junctionPrefix = OptionsCont::getOptions().getString("prefix") + OptionsCont::getOptions().getString("node-prefix");
while (myAttributeCarriers->getJunctions().count(junctionPrefix + toString(myJunctionIDCounter)) != 0) {
myJunctionIDCounter++;
}
NBNode* nbn = new NBNode(junctionPrefix + toString(myJunctionIDCounter), pos);
GNEJunction* junction = new GNEJunction(this, nbn);
undoList->add(new GNEChange_Junction(junction, true), true);
return junction;
}
GNEEdge*
GNENet::createEdge(GNEJunction* src, GNEJunction* dest, GNEEdge* edgeTemplate, GNEUndoList* undoList,
const std::string& suggestedName, bool wasSplit, bool allowDuplicateGeom, bool recomputeConnections) {
for (const auto& outgoingEdge : src->getNBNode()->getOutgoingEdges()) {
if (outgoingEdge->getToNode() == dest->getNBNode() && outgoingEdge->getGeometry().size() == 2) {
if (!allowDuplicateGeom) {
return nullptr;
}
}
}
const auto oppositeEdges = myAttributeCarriers->retrieveEdges(dest, src);
const std::string edgePrefix = OptionsCont::getOptions().getString("prefix") + OptionsCont::getOptions().getString("edge-prefix");
std::string edgeInfix = OptionsCont::getOptions().getString("edge-infix");
std::string edgeID;
if (oppositeEdges.size() > 0) {
if ((oppositeEdges.front()->getID().size() > 1) && (oppositeEdges.front()->getID().front() == '-')) {
edgeID = oppositeEdges.front()->getID().substr(1);
} else {
edgeID = "-" + oppositeEdges.front()->getID();
}
if (myAttributeCarriers->getEdges().count(edgeID) > 0) {
int counter = 0;
while (myAttributeCarriers->getEdges().count(edgeID + toString(counter)) > 0) {
counter++;
}
edgeID = edgeID + toString(counter);
}
} else if ((suggestedName.size() > 0) && (myAttributeCarriers->retrieveEdge(suggestedName, false) == nullptr)) {
edgeID = suggestedName;
} else if (edgeInfix.size() > 0) {
edgeInfix = StringUtils::trim(edgeInfix);
if (myAttributeCarriers->getEdges().count(src->getID() + edgeInfix + dest->getID()) == 0) {
edgeID = src->getID() + edgeInfix + dest->getID();
} else {
int counter = 0;
while (myAttributeCarriers->getEdges().count(src->getID() + edgeInfix + toString(counter) + dest->getID()) != 0) {
myEdgeIDCounter++;
}
edgeID = src->getID() + edgeInfix + toString(counter) + dest->getID();
}
} else {
edgeID = myAttributeCarriers->generateEdgeID();
}
GNEEdge* edge;
if (edgeTemplate) {
NBEdge* nbe = new NBEdge(edgeID, src->getNBNode(), dest->getNBNode(), edgeTemplate->getNBEdge());
edge = new GNEEdge(this, nbe, wasSplit);
} else {
const auto& neteditOptions = OptionsCont::getOptions();
double defaultSpeed = neteditOptions.getFloat("default.speed");
const std::string defaultType = neteditOptions.getString("default.type");
const int defaultNrLanes = neteditOptions.getInt("default.lanenumber");
const int defaultPriority = neteditOptions.getInt("default.priority");
const double defaultWidth = NBEdge::UNSPECIFIED_WIDTH;
const double defaultOffset = NBEdge::UNSPECIFIED_OFFSET;
const LaneSpreadFunction spread = LaneSpreadFunction::RIGHT;
NBEdge* nbe = new NBEdge(edgeID, src->getNBNode(), dest->getNBNode(),
defaultType, defaultSpeed, NBEdge::UNSPECIFIED_FRICTION,
defaultNrLanes, defaultPriority,
defaultWidth, defaultOffset, spread);
edge = new GNEEdge(this, nbe, wasSplit);
}
undoList->begin(edge, TL("create edge"));
undoList->add(new GNEChange_Edge(edge, true), true);
if (recomputeConnections) {
src->setLogicValid(false, undoList);
dest->setLogicValid(false, undoList);
}
requireRecompute();
undoList->end();
return edge;
}
void
GNENet::deleteNetworkElement(GNENetworkElement* networkElement, GNEUndoList* undoList) {
if (networkElement->getTagProperty()->getTag() == SUMO_TAG_JUNCTION) {
GNEJunction* junction = myAttributeCarriers->retrieveJunction(networkElement->getID(), false);
if (junction) {
deleteJunction(junction, undoList);
}
} else if (networkElement->getTagProperty()->getTag() == SUMO_TAG_CROSSING) {
GNECrossing* crossing = myAttributeCarriers->retrieveCrossing(networkElement->getGUIGlObject(), false);
if (crossing) {
deleteCrossing(crossing, undoList);
}
} else if (networkElement->getTagProperty()->getTag() == SUMO_TAG_EDGE) {
GNEEdge* edge = myAttributeCarriers->retrieveEdge(networkElement->getID(), false);
if (edge) {
deleteEdge(edge, undoList, false);
}
} else if (networkElement->getTagProperty()->getTag() == SUMO_TAG_LANE) {
GNELane* lane = myAttributeCarriers->retrieveLane(networkElement->getGUIGlObject(), false);
if (lane) {
deleteLane(lane, undoList, false);
}
} else if (networkElement->getTagProperty()->getTag() == SUMO_TAG_CONNECTION) {
GNEConnection* connection = myAttributeCarriers->retrieveConnection(networkElement->getGUIGlObject(), false);
if (connection) {
deleteConnection(connection, undoList);
}
}
}
void
GNENet::deleteJunction(GNEJunction* junction, GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("delete junction"));
myNetworkPathManager->invalidateJunctionPath(junction);
myDemandPathManager->invalidateJunctionPath(junction);
myDataPathManager->invalidateJunctionPath(junction);
while (junction->getChildDemandElements().size() > 0) {
deleteDemandElement(junction->getChildDemandElements().front(), undoList);
}
while (junction->getGNECrossings().size() > 0) {
deleteCrossing(junction->getGNECrossings().front(), undoList);
}
std::vector<GNECrossing*> crossingsToRemove;
std::vector<GNEJunction*> junctionNeighbours = junction->getJunctionNeighbours();
for (const auto& junctionNeighbour : junctionNeighbours) {
for (const auto& crossing : junctionNeighbour->getGNECrossings()) {
if (crossing->checkEdgeBelong(junction->getChildEdges())) {
crossingsToRemove.push_back(crossing);
}
}
}
for (const auto& crossing : crossingsToRemove) {
deleteCrossing(crossing, undoList);
}
const EdgeVector incidentEdges = junction->getNBNode()->getEdges();
for (const auto& edge : incidentEdges) {
deleteEdge(myAttributeCarriers->getEdges().at(edge->getID()), undoList, true);
}
junction->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::PRIORITY), undoList);
undoList->add(new GNEChange_Junction(junction, false), true);
undoList->end();
}
void
GNENet::deleteEdge(GNEEdge* edge, GNEUndoList* undoList, bool recomputeConnections) {
undoList->begin(GUIIcon::MODEDELETE, TL("delete edge"));
for (const auto& lane : edge->getChildLanes()) {
myNetworkPathManager->invalidateLanePath(lane);
myDemandPathManager->invalidateLanePath(lane);
myDataPathManager->invalidateLanePath(lane);
while (lane->getChildAdditionals().size() > 0) {
deleteAdditional(lane->getChildAdditionals().front(), undoList);
}
while (lane->getChildDemandElements().size() > 0) {
deleteDemandElement(lane->getChildDemandElements().front(), undoList);
}
while (lane->getChildGenericDatas().size() > 0) {
deleteGenericData(lane->getChildGenericDatas().front(), undoList);
}
}
while (edge->getChildAdditionals().size() > 0) {
deleteAdditional(edge->getChildAdditionals().front(), undoList);
}
while (edge->getChildTAZSourceSinks().size() > 0) {
deleteTAZSourceSink(*edge->getChildTAZSourceSinks().begin(), undoList);
}
while (edge->getChildDemandElements().size() > 0) {
if (edge->getChildDemandElements().front()->getTagProperty()->getTag() == GNE_TAG_ROUTE_EMBEDDED) {
deleteDemandElement(edge->getChildDemandElements().front()->getParentDemandElements().front(), undoList);
} else if (edge->getChildDemandElements().front()->getTagProperty()->isPlan()) {
const auto planParent = edge->getChildDemandElements().front()->getParentDemandElements().front();
if (planParent->getChildDemandElements().size() == 1) {
deleteDemandElement(planParent, undoList);
} else {
deleteDemandElement(edge->getChildDemandElements().front(), undoList);
}
} else {
deleteDemandElement(edge->getChildDemandElements().front(), undoList);
}
}
while (edge->getChildGenericDatas().size() > 0) {
deleteGenericData(edge->getChildGenericDatas().front(), undoList);
}
edge->getFromJunction()->removeEdgeFromCrossings(edge, undoList);
edge->getToJunction()->removeEdgeFromCrossings(edge, undoList);
if (recomputeConnections) {
edge->getFromJunction()->setLogicValid(false, undoList);
edge->getToJunction()->setLogicValid(false, undoList);
} else {
edge->getFromJunction()->removeConnectionsTo(edge, undoList, true);
edge->getToJunction()->removeConnectionsFrom(edge, undoList, true);
}
if (edge->getFromJunction()->getNBNode()->isTLControlled() && (edge->getFromJunction()->getGNEOutgoingEdges().size() <= 1)) {
edge->getFromJunction()->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::PRIORITY), undoList);
}
if (edge->getToJunction()->getNBNode()->isTLControlled() && (edge->getToJunction()->getGNEIncomingEdges().size() <= 1)) {
edge->getToJunction()->setAttribute(SUMO_ATTR_TYPE, toString(SumoXMLNodeType::PRIORITY), undoList);
}
const std::string oppLaneID = edge->getChildLanes().back()->getAttribute(GNE_ATTR_OPPOSITE);
if (oppLaneID != "") {
GNELane* lane = myAttributeCarriers->retrieveLane(oppLaneID, false);
if (lane != nullptr) {
lane->setAttribute(GNE_ATTR_OPPOSITE, "", undoList);
}
}
undoList->add(new GNEChange_Edge(edge, false), true);
requireRecompute();
undoList->end();
}
void
GNENet::replaceIncomingEdge(GNEEdge* which, GNEEdge* by, GNEUndoList* undoList) {
undoList->begin(which, TL("replace edge"));
GNEChange_Attribute::changeAttribute(by, SUMO_ATTR_TO, which->getAttribute(SUMO_ATTR_TO), undoList);
for (const auto& lane : which->getChildLanes()) {
std::vector<GNEAdditional*> copyOfLaneAdditionals = lane->getChildAdditionals();
for (const auto& additional : copyOfLaneAdditionals) {
GNEChange_Attribute::changeAttribute(additional, SUMO_ATTR_LANE, by->getNBEdge()->getLaneID(lane->getIndex()), undoList);
if (additional->hasAttribute(SUMO_ATTR_STARTPOS)) {
GNEChange_Attribute::changeAttribute(additional, SUMO_ATTR_STARTPOS,
toString(StringUtils::toDouble(additional->getAttribute(SUMO_ATTR_STARTPOS)) + which->getNBEdge()->getFinalLength()),
undoList);
}
if (additional->hasAttribute(SUMO_ATTR_ENDPOS)) {
GNEChange_Attribute::changeAttribute(additional, SUMO_ATTR_ENDPOS,
toString(StringUtils::toDouble(additional->getAttribute(SUMO_ATTR_ENDPOS)) + which->getNBEdge()->getFinalLength()),
undoList);
}
}
std::vector<GNEDemandElement*> copyOfLaneDemandElements = lane->getChildDemandElements();
for (const auto& demandElement : copyOfLaneDemandElements) {
GNEChange_Attribute::changeAttribute(demandElement, SUMO_ATTR_LANE, by->getNBEdge()->getLaneID(lane->getIndex()), undoList);
}
std::vector<GNEGenericData*> copyOfLaneGenericDatas = lane->getChildGenericDatas();
for (const auto& demandElement : copyOfLaneGenericDatas) {
GNEChange_Attribute::changeAttribute(demandElement, SUMO_ATTR_LANE, by->getNBEdge()->getLaneID(lane->getIndex()), undoList);
}
}
std::vector<GNEAdditional*> addElements = which->getChildAdditionals();
for (GNEAdditional* add : addElements) {
if (add->hasAttribute(SUMO_ATTR_EDGE)) {
GNEChange_Attribute::changeAttribute(add, SUMO_ATTR_EDGE, by->getID(), undoList);
}
}
const std::vector<GNEDemandElement*> demandElements = which->getChildDemandElements();
for (GNEDemandElement* demandElement : demandElements) {
if (demandElement->hasAttribute(SUMO_ATTR_EDGE)) {
GNEChange_Attribute::changeAttribute(demandElement, SUMO_ATTR_EDGE, by->getID(), undoList);
}
if (demandElement->hasAttribute(SUMO_ATTR_EDGES)) {
replaceInListAttribute(demandElement, SUMO_ATTR_EDGES, which->getID(), by->getID(), undoList);
}
if (demandElement->hasAttribute(SUMO_ATTR_VIA)) {
replaceInListAttribute(demandElement, SUMO_ATTR_VIA, which->getID(), by->getID(), undoList);
}
if (demandElement->hasAttribute(SUMO_ATTR_FROM) && demandElement->getAttribute(SUMO_ATTR_FROM) == which->getID()) {
GNEChange_Attribute::changeAttribute(demandElement, SUMO_ATTR_FROM, by->getID(), undoList);
}
if (demandElement->hasAttribute(SUMO_ATTR_TO) && demandElement->getAttribute(SUMO_ATTR_TO) == which->getID()) {
GNEChange_Attribute::changeAttribute(demandElement, SUMO_ATTR_TO, by->getID(), undoList);
}
}
const std::vector<GNEGenericData*> dataElements = which->getChildGenericDatas();
for (GNEGenericData* dataElement : dataElements) {
if (dataElement->hasAttribute(SUMO_ATTR_EDGE)) {
GNEChange_Attribute::changeAttribute(dataElement, SUMO_ATTR_EDGE, by->getID(), undoList);
}
}
addElements = which->getParentAdditionals();
for (GNEAdditional* add : addElements) {
if (add->hasAttribute(SUMO_ATTR_EDGES)) {
replaceInListAttribute(add, SUMO_ATTR_EDGES, which->getID(), by->getID(), undoList);
}
}
for (const auto& crossing : which->getToJunction()->getGNECrossings()) {
replaceInListAttribute(crossing, SUMO_ATTR_EDGES, which->getID(), by->getID(), undoList);
}
std::vector<NBEdge::Connection> NBConnections = which->getNBEdge()->getConnections();
for (const auto& NBConnection : NBConnections) {
if (NBConnection.toEdge != nullptr) {
undoList->add(new GNEChange_Connection(which, NBConnection, false, false), true);
undoList->add(new GNEChange_Connection(by, NBConnection, false, true), true);
}
}
undoList->add(new GNENetHelper::GNEChange_ReplaceEdgeInTLS(getTLLogicCont(), which->getNBEdge(), by->getNBEdge()), true);
undoList->add(new GNEChange_Edge(which, false), true);
undoList->end();
}
void
GNENet::deleteLane(GNELane* lane, GNEUndoList* undoList, bool recomputeConnections) {
GNEEdge* edge = lane->getParentEdge();
if (edge->getNBEdge()->getNumLanes() == 1) {
deleteEdge(edge, undoList, recomputeConnections);
} else {
undoList->begin(GUIIcon::MODEDELETE, TL("delete lane"));
myNetworkPathManager->invalidateLanePath(lane);
myDemandPathManager->invalidateLanePath(lane);
myDataPathManager->invalidateLanePath(lane);
while (lane->getChildAdditionals().size() > 0) {
deleteAdditional(lane->getChildAdditionals().front(), undoList);
}
while (lane->getChildDemandElements().size() > 0) {
deleteDemandElement(lane->getChildDemandElements().front(), undoList);
}
while (lane->getChildGenericDatas().size() > 0) {
deleteGenericData(lane->getChildGenericDatas().front(), undoList);
}
if (recomputeConnections) {
edge->getFromJunction()->setLogicValid(false, undoList);
edge->getToJunction()->setLogicValid(false, undoList);
} else {
edge->getFromJunction()->removeConnectionsTo(edge, undoList, true, lane->getIndex());
edge->getToJunction()->removeConnectionsFrom(edge, undoList, true, lane->getIndex());
}
const NBEdge::Lane& laneAttrs = edge->getNBEdge()->getLaneStruct(lane->getIndex());
undoList->add(new GNEChange_Lane(edge, lane, laneAttrs, false, recomputeConnections), true);
requireRecompute();
undoList->end();
}
}
void
GNENet::deleteConnection(GNEConnection* connection, GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("delete connection"));
NBConnection deleted = connection->getNBConnection();
GNEJunction* junctionDestination = connection->getEdgeFrom()->getToJunction();
junctionDestination->markAsModified(undoList);
undoList->add(new GNEChange_Connection(connection->getEdgeFrom(), connection->getNBEdgeConnection(), connection->isAttributeCarrierSelected(), false), true);
junctionDestination->invalidateTLS(undoList, deleted);
requireRecompute();
undoList->end();
}
void
GNENet::deleteCrossing(GNECrossing* crossing, GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("delete crossing"));
undoList->add(new GNEChange_Crossing(
crossing->getParentJunctions().front(), crossing->getNBCrossing()->edges,
crossing->getNBCrossing()->width, crossing->getNBCrossing()->priority,
crossing->getNBCrossing()->customTLIndex,
crossing->getNBCrossing()->customTLIndex2,
crossing->getNBCrossing()->customShape,
crossing->isAttributeCarrierSelected(),
false), true);
requireRecompute();
undoList->end();
}
void
GNENet::deleteAdditional(GNEAdditional* additional, GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + additional->getTagStr());
while (additional->getChildDemandElements().size() > 0) {
deleteDemandElement(additional->getChildDemandElements().front(), undoList);
}
while (additional->getChildGenericDatas().size() > 0) {
deleteGenericData(additional->getChildGenericDatas().front(), undoList);
}
while (additional->getChildAdditionals().size() > 0) {
deleteAdditional(additional->getChildAdditionals().front(), undoList);
}
while (additional->getChildTAZSourceSinks().size() > 0) {
deleteTAZSourceSink(*additional->getChildTAZSourceSinks().begin(), undoList);
}
undoList->add(new GNEChange_Additional(additional, false), true);
undoList->end();
}
void
GNENet::deleteTAZSourceSink(GNETAZSourceSink* TAZSourceSink, GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + TAZSourceSink->getTagStr());
undoList->add(new GNEChange_TAZSourceSink(TAZSourceSink, false), true);
undoList->end();
}
void
GNENet::deleteDemandElement(GNEDemandElement* demandElement, GNEUndoList* undoList) {
if ((demandElement->getTagProperty()->getTag() == SUMO_TAG_VTYPE) && (GNEAttributeCarrier::parse<bool>(demandElement->getAttribute(GNE_ATTR_DEFAULT_VTYPE)))) {
throw ProcessError(TL("Trying to delete a default Vehicle Type"));
} else {
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + demandElement->getTagStr());
while (demandElement->getChildAdditionals().size() > 0) {
deleteAdditional(demandElement->getChildAdditionals().front(), undoList);
}
while (demandElement->getChildDemandElements().size() > 0) {
deleteDemandElement(demandElement->getChildDemandElements().front(), undoList);
}
while (demandElement->getChildGenericDatas().size() > 0) {
deleteGenericData(demandElement->getChildGenericDatas().front(), undoList);
}
undoList->add(new GNEChange_DemandElement(demandElement, false), true);
undoList->end();
}
}
void
GNENet::deleteDataSet(GNEDataSet* dataSet, GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + dataSet->getTagStr());
auto copyOfDataIntervalChildren = dataSet->getDataIntervalChildren();
for (const auto& dataInterval : copyOfDataIntervalChildren) {
deleteDataInterval(dataInterval.second, undoList);
}
undoList->end();
}
void
GNENet::deleteDataInterval(GNEDataInterval* dataInterval, GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + dataInterval->getTagStr());
auto copyOfGenericDataChildren = dataInterval->getGenericDataChildren();
for (const auto& genericData : copyOfGenericDataChildren) {
deleteGenericData(genericData, undoList);
}
undoList->end();
}
void
GNENet::deleteGenericData(GNEGenericData* genericData, GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + genericData->getTagStr());
while (genericData->getChildDemandElements().size() > 0) {
deleteDemandElement(genericData->getChildDemandElements().front(), undoList);
}
while (genericData->getChildGenericDatas().size() > 0) {
deleteGenericData(genericData->getChildGenericDatas().front(), undoList);
}
GNEDataInterval* dataInterval = genericData->getDataIntervalParent();
GNEDataSet* dataSet = dataInterval->getDataSetParent();
undoList->add(new GNEChange_GenericData(genericData, false), true);
if (dataInterval->getGenericDataChildren().empty()) {
undoList->add(new GNEChange_DataInterval(genericData->getDataIntervalParent(), false), true);
if (dataSet->getDataIntervalChildren().empty()) {
undoList->add(new GNEChange_DataSet(genericData->getDataIntervalParent()->getDataSetParent(), false), true);
}
}
undoList->end();
}
void
GNENet::deleteMeanData(GNEMeanData* meanData, GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("delete ") + meanData->getTagStr());
undoList->add(new GNEChange_MeanData(meanData, false), true);
undoList->end();
}
void
GNENet::duplicateLane(GNELane* lane, GNEUndoList* undoList, bool recomputeConnections) {
undoList->begin(lane, TL("duplicate lane"));
GNEEdge* edge = lane->getParentEdge();
const NBEdge::Lane& laneAttrs = edge->getNBEdge()->getLaneStruct(lane->getIndex());
if (recomputeConnections) {
edge->getFromJunction()->setLogicValid(false, undoList);
edge->getToJunction()->setLogicValid(false, undoList);
}
GNELane* newLane = new GNELane(edge, lane->getIndex());
undoList->add(new GNEChange_Lane(edge, newLane, laneAttrs, true, recomputeConnections), true);
requireRecompute();
undoList->end();
}
bool
GNENet::restrictLane(SUMOVehicleClass vclass, GNELane* lane, GNEUndoList* undoList) {
bool addRestriction = true;
if (vclass == SVC_PEDESTRIAN) {
GNEEdge* edge = lane->getParentEdge();
for (const auto& edgeLane : edge->getChildLanes()) {
if (edgeLane->isRestricted(SVC_PEDESTRIAN)) {
addRestriction = false;
} else {
const SVCPermissions allOldWithoutPeds = edge->getNBEdge()->getPermissions(edgeLane->getIndex()) & ~SVC_PEDESTRIAN;
edgeLane->setAttribute(SUMO_ATTR_ALLOW, getVehicleClassNames(allOldWithoutPeds), undoList);
}
}
}
if (addRestriction) {
double width;
if (vclass == SVC_PEDESTRIAN) {
width = OptionsCont::getOptions().getFloat("default.sidewalk-width");
} else if (vclass == SVC_BICYCLE) {
width = OptionsCont::getOptions().getFloat("default.bikelane-width");
} else {
width = OptionsCont::getOptions().getFloat("default.lanewidth");
}
lane->setAttribute(SUMO_ATTR_ALLOW, toString(vclass), undoList);
lane->setAttribute(SUMO_ATTR_WIDTH, toString(width), undoList);
if ((vclass & ~SVC_PEDESTRIAN) == 0) {
std::vector<GNEConnection*> cons;
const bool reguess = lane->getParentEdge()->getNBEdge()->getStep() <= NBEdge::EdgeBuildingStep::LANES2LANES_RECHECK;
if (reguess) {
cons = lane->getParentEdge()->getGNEConnections();
} else {
cons = lane->getGNEOutcomingConnections();
}
for (auto c : cons) {
undoList->add(new GNEChange_Connection(lane->getParentEdge(), c->getNBEdgeConnection(), false, false), true);
}
if (reguess) {
GNEChange_Attribute::changeAttribute(lane->getParentEdge(), GNE_ATTR_MODIFICATION_STATUS, GNEAttributeCarrier::FEATURE_GUESSED, undoList, true);
}
}
return true;
} else {
return false;
}
}
bool
GNENet::addRestrictedLane(SUMOVehicleClass vclass, GNEEdge* edge, int index, GNEUndoList* undoList) {
for (const auto& lane : edge->getChildLanes()) {
if (lane->isRestricted(vclass)) {
return false;
}
}
const int numLanes = (int)edge->getChildLanes().size();
if (index > numLanes) {
return false;
}
if (index < 0) {
index = 0;
if (vclass == SVC_BICYCLE) {
index = edge->getChildLanes()[0]->isRestricted(SVC_PEDESTRIAN) ? 1 : 0;
} else if (vclass == SVC_BUS) {
index = 0;
while (index < numLanes && (edge->getNBEdge()->getPermissions(index) & ~(SVC_PEDESTRIAN | SVC_BICYCLE)) == 0) {
index++;
}
}
}
duplicateLane(edge->getChildLanes().at(MIN2(index, numLanes - 1)), undoList, true);
return restrictLane(vclass, edge->getChildLanes().at(index), undoList);
}
bool
GNENet::addGreenVergeLane(GNEEdge* edge, int index, GNEUndoList* undoList) {
const int numLanes = (int)edge->getChildLanes().size();
if (index > numLanes) {
index = numLanes;
}
if (index < 0) {
index = 0;
}
duplicateLane(edge->getChildLanes().at(MIN2(index, numLanes - 1)), undoList, true);
return restrictLane(SVC_IGNORING, edge->getChildLanes().at(index), undoList);
}
bool
GNENet::removeRestrictedLane(SUMOVehicleClass vclass, GNEEdge* edge, GNEUndoList* undoList) {
for (const auto& lane : edge->getChildLanes()) {
if (lane->isRestricted(vclass)) {
deleteLane(lane, undoList, true);
return true;
}
}
return false;
}
std::pair<GNEJunction*, GNEEdge*>
GNENet::splitEdge(GNEEdge* edge, const Position& pos, GNEUndoList* undoList, GNEJunction* newJunction) {
undoList->begin(edge, TL("split edge"));
if (newJunction == nullptr) {
newJunction = createJunction(pos, undoList);
}
const PositionVector& oldEdgeGeometry = edge->getNBEdge()->getGeometry();
const double edgeSplitPosition = oldEdgeGeometry.nearest_offset_to_point2D(pos, false);
const PositionVector& oldLaneGeometry = edge->getChildLanes().front()->getLaneShape();
const double laneSplitPosition = oldLaneGeometry.nearest_offset_to_point2D(pos, false);
std::pair<PositionVector, PositionVector> newGeoms = oldEdgeGeometry.splitAt(edgeSplitPosition);
const double oldLength = oldEdgeGeometry.length();
const double relativeLength1 = oldLength != 0 ? newGeoms.first.length() / oldLength : 1;
const double relativeLength2 = oldLength != 0 ? newGeoms.second.length() / oldLength : 1;
const std::string shapeEnd = edge->getAttribute(GNE_ATTR_SHAPE_END);
int posBase = 0;
std::string baseName = edge->getMicrosimID();
if (edge->wasSplit()) {
const std::string::size_type sep_index = baseName.rfind('.');
if (sep_index != std::string::npos) {
std::string posString = baseName.substr(sep_index + 1);
if (GNEAttributeCarrier::canParse<int>(posString.c_str())) {
;
posBase = GNEAttributeCarrier::parse<int>(posString.c_str());
baseName = baseName.substr(0, sep_index);
}
}
}
baseName += '.';
GNEEdge* secondPart = createEdge(newJunction, edge->getToJunction(), edge,
undoList, baseName + toString(posBase + (int)edgeSplitPosition), true, false, false);
edge->getToJunction()->replaceIncomingConnections(edge, secondPart, undoList);
std::vector<NBNode::Crossing> affectedCrossings;
for (GNECrossing* crossing : edge->getToJunction()->getGNECrossings()) {
if (crossing->checkEdgeBelong(edge)) {
NBNode::Crossing nbC = *crossing->getNBCrossing();
undoList->add(new GNEChange_Crossing(edge->getToJunction(), nbC, false), true);
EdgeVector newEdges;
for (NBEdge* nbEdge : nbC.edges) {
if (nbEdge == edge->getNBEdge()) {
newEdges.push_back(secondPart->getNBEdge());
} else {
newEdges.push_back(nbEdge);
}
}
nbC.edges = newEdges;
affectedCrossings.push_back(nbC);
}
}
GNEChange_Attribute::changeAttribute(edge, SUMO_ATTR_TO, newJunction->getID(), undoList);
newGeoms.first.pop_back();
newGeoms.first.erase(newGeoms.first.begin());
edge->setAttribute(GNE_ATTR_SHAPE_END, "", undoList);
edge->setAttribute(SUMO_ATTR_SHAPE, toString(newGeoms.first), undoList);
secondPart->setAttribute(GNE_ATTR_SHAPE_END, shapeEnd, undoList);
newGeoms.second.pop_back();
newGeoms.second.erase(newGeoms.second.begin());
secondPart->setAttribute(SUMO_ATTR_SHAPE, toString(newGeoms.second), undoList);
if (edge->getNBEdge()->hasLoadedLength()) {
const double loadedLength = edge->getNBEdge()->getLoadedLength();
edge->setAttribute(SUMO_ATTR_LENGTH, toString(relativeLength1 * loadedLength), undoList);
secondPart->setAttribute(SUMO_ATTR_LENGTH, toString(relativeLength2 * loadedLength), undoList);
}
for (int i = 0; i < (int)edge->getChildLanes().size(); ++i) {
undoList->add(new GNEChange_Connection(edge, NBEdge::Connection(i, secondPart->getNBEdge(), i), false, true), true);
}
for (const auto& nbC : affectedCrossings) {
undoList->add(new GNEChange_Crossing(secondPart->getToJunction(), nbC, true), true);
}
auto childAdditionals = edge->getChildAdditionals();
for (const auto& additional : childAdditionals) {
additional->splitEdgeGeometry(edgeSplitPosition, edge, secondPart, undoList);
}
for (int i = 0; i < (int)edge->getChildLanes().size(); i++) {
for (const auto& additional : edge->getChildLanes().at(i)->getChildAdditionals()) {
additional->splitEdgeGeometry(laneSplitPosition, edge->getChildLanes().at(i), secondPart->getChildLanes().at(i), undoList);
}
}
auto childDemandElements = edge->getChildDemandElements();
for (const auto& demandElement : childDemandElements) {
demandElement->splitEdgeGeometry(edgeSplitPosition, edge, secondPart, undoList);
}
for (int i = 0; i < (int)edge->getChildLanes().size(); i++) {
for (const auto& demandElement : edge->getChildLanes().at(i)->getChildDemandElements()) {
demandElement->splitEdgeGeometry(laneSplitPosition, edge->getChildLanes().at(i), secondPart->getChildLanes().at(i), undoList);
}
}
undoList->end();
return std::make_pair(newJunction, secondPart);
}
void
GNENet::splitEdgesBidi(GNEEdge* edge, GNEEdge* oppositeEdge, const Position& pos, GNEUndoList* undoList) {
GNEJunction* newJunction = nullptr;
undoList->begin(edge, TL("split edges"));
auto newStuff = splitEdge(edge, pos, undoList, newJunction);
newJunction = newStuff.first;
splitEdge(oppositeEdge, pos, undoList, newJunction);
if (edge->getChildLanes().back()->getAttribute(GNE_ATTR_OPPOSITE) != "") {
for (const auto& nbEdge : newJunction->getNBNode()->getEdges()) {
GNEEdge* e = myAttributeCarriers->retrieveEdge(nbEdge->getID());
e->getChildLanes().back()->setAttribute(GNE_ATTR_OPPOSITE, "", undoList);
if (nbEdge->guessOpposite(true)) {
e->getChildLanes().back()->setAttribute(GNE_ATTR_OPPOSITE, nbEdge->getLanes().back().oppositeID, undoList);
}
}
}
undoList->end();
}
void
GNENet::reverseEdge(GNEEdge* edge, GNEUndoList* undoList) {
undoList->begin(edge, TL("reverse edge"));
auto fromJunction = edge->getFromJunction();
auto ToJunction = edge->getToJunction();
deleteEdge(edge, undoList, false);
GNEEdge* reversed = createEdge(ToJunction, fromJunction, edge, undoList, edge->getID(), false, true);
if (reversed) {
reversed->setAttribute(SUMO_ATTR_SHAPE, toString(edge->getNBEdge()->getInnerGeometry().reverse()), undoList);
reversed->setAttribute(GNE_ATTR_SHAPE_START, edge->getAttribute(GNE_ATTR_SHAPE_END), undoList);
reversed->setAttribute(GNE_ATTR_SHAPE_END, edge->getAttribute(GNE_ATTR_SHAPE_START), undoList);
}
undoList->end();
}
GNEEdge*
GNENet::addReversedEdge(GNEEdge* edge, const bool disconnected, GNEUndoList* undoList) {
GNEEdge* reversed = edge->getReverseEdge();
if (reversed != nullptr) {
return reversed;
}
undoList->begin(edge, TL("add reversed edge"));
if (!disconnected) {
reversed = createEdge(edge->getToJunction(), edge->getFromJunction(), edge, undoList, "-" + edge->getID(), false, true);
assert(reversed != 0);
reversed->setAttribute(SUMO_ATTR_SHAPE, toString(edge->getNBEdge()->getInnerGeometry().reverse()), undoList);
reversed->setAttribute(GNE_ATTR_SHAPE_START, edge->getAttribute(GNE_ATTR_SHAPE_END), undoList);
reversed->setAttribute(GNE_ATTR_SHAPE_END, edge->getAttribute(GNE_ATTR_SHAPE_START), undoList);
} else {
PositionVector orig = edge->getNBEdge()->getGeometry();
PositionVector origInner = edge->getNBEdge()->getInnerGeometry();
const double tentativeShift = edge->getNBEdge()->getTotalWidth() + 2;
orig.move2side(-tentativeShift);
origInner.move2side(-tentativeShift);
GNEJunction* src = createJunction(orig.back(), undoList);
GNEJunction* dest = createJunction(orig.front(), undoList);
reversed = createEdge(src, dest, edge, undoList, "-" + edge->getID(), false, true);
assert(reversed != 0);
reversed->setAttribute(SUMO_ATTR_SHAPE, toString(origInner.reverse()), undoList);
reversed->setAttribute(SUMO_ATTR_SHAPE, toString(origInner.reverse()), undoList);
reversed->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
src->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
dest->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
}
undoList->end();
return reversed;
}
void
GNENet::mergeJunctions(GNEJunction* moved, const GNEJunction* target, GNEUndoList* undoList) {
undoList->begin(moved, TL("merge junctions"));
const EdgeVector incomingNBEdges = moved->getNBNode()->getIncomingEdges();
for (const auto& incomingNBEdge : incomingNBEdges) {
GNEEdge* edge = myAttributeCarriers->getEdges().at(incomingNBEdge->getID());
if (edge->getFromJunction() == target) {
deleteEdge(edge, undoList, false);
} else {
edge->setAttribute(SUMO_ATTR_TO, target->getID(), undoList);
}
}
const EdgeVector outgoingNBEdges = moved->getNBNode()->getOutgoingEdges();
for (const auto& outgoingNBEdge : outgoingNBEdges) {
GNEEdge* edge = myAttributeCarriers->getEdges().at(outgoingNBEdge->getID());
if (edge->getToJunction() == target) {
deleteEdge(edge, undoList, false);
} else {
edge->setAttribute(SUMO_ATTR_FROM, target->getID(), undoList);
}
}
deleteJunction(moved, undoList);
undoList->end();
}
void
GNENet::selectRoundabout(GNEJunction* junction, GNEUndoList* undoList) {
for (const EdgeSet& roundabout : myNetBuilder->getEdgeCont().getRoundabouts()) {
for (NBEdge* edge : roundabout) {
if (edge->getFromNode() == junction->getNBNode()) {
undoList->begin(junction, TL("select roundabout"));
for (const auto& roundaboutEdge : roundabout) {
GNEEdge* e = myAttributeCarriers->retrieveEdge(roundaboutEdge->getID());
e->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
e->getToJunction()->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
}
undoList->end();
return;
}
}
}
}
void
GNENet::createRoundabout(GNEJunction* junction, GNEUndoList* undoList) {
undoList->begin(junction, TL("create roundabout"));
for (const auto& incomingEdge : junction->getGNEIncomingEdges()) {
incomingEdge->setAttribute(GNE_ATTR_SHAPE_END, "", undoList);
}
for (const auto& outgoingEdge : junction->getGNEOutgoingEdges()) {
outgoingEdge->setAttribute(GNE_ATTR_SHAPE_START, "", undoList);
}
junction->getNBNode()->updateSurroundingGeometry();
double radius = junction->getNBNode()->getRadius();
if (radius == NBNode::UNSPECIFIED_RADIUS) {
radius = OptionsCont::getOptions().getFloat("default.junctions.radius");
}
std::vector<GNEEdge*> edges;
for (const auto& nbEdge : junction->getNBNode()->getEdges()) {
edges.push_back(myAttributeCarriers->retrieveEdge(nbEdge->getID()));
}
const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
if (lefthand) {
std::reverse(edges.begin(), edges.end());
}
const double lefthandSign = lefthand ? -1 : 1;
std::vector<GNEJunction*> newJunctions;
GNEEdge* templateEdge = nullptr;
GNEEdge* prevOpposite = nullptr;
std::vector<std::pair<NBNode::Crossing, std::vector<std::string>>> oldCrossings;
for (const auto& crossing : junction->getGNECrossings()) {
std::vector<std::string> edgeIDs;
for (auto e : crossing->getCrossingEdges()) {
edgeIDs.push_back(e->getID());
}
oldCrossings.push_back(std::make_pair(*crossing->getNBCrossing(), edgeIDs));
}
std::map<std::string, std::string> edgeRename;
for (GNEEdge* edge : edges) {
GNEJunction* newJunction = nullptr;
if (edge == prevOpposite) {
newJunction = newJunctions.back();
}
if (edge->getToJunction() == junction) {
if (templateEdge == nullptr) {
templateEdge = edge;
} else {
NBEdge* tpl = templateEdge->getNBEdge();
NBEdge* e = edge->getNBEdge();
if (tpl->getNumLanes() < e->getNumLanes()
|| (tpl->getNumLanes() == e->getNumLanes()
&& tpl->getPriority() < e->getPriority())) {
templateEdge = edge;
}
}
}
prevOpposite = edge->getOppositeEdges().size() > 0 ? edge->getOppositeEdges().front() : nullptr;
const double geomLength = edge->getNBEdge()->getGeometry().length2D();
const double splitOffset = (edge->getToJunction() == junction
? MAX2(POSITION_EPS, geomLength - radius)
: MIN2(geomLength - POSITION_EPS, radius));
Position pos = edge->getNBEdge()->getGeometry().positionAtOffset2D(splitOffset);
auto newStuff = splitEdge(edge, pos, undoList, newJunction);
newJunction = newStuff.first;
if (edge->getFromJunction() == junction) {
edgeRename[newStuff.second->getID()] = edge->getID();
}
if (newJunctions.empty() || newJunction != newJunctions.back()) {
newJunctions.push_back(newJunction);
}
}
Position center = junction->getPositionInView();
deleteJunction(junction, undoList);
for (auto item : edgeRename) {
GNEEdge* outgoing = myAttributeCarriers->retrieveEdge(item.first);
outgoing->setAttribute(SUMO_ATTR_ID, item.second, undoList);
}
for (auto nbCItem : oldCrossings) {
for (GNEJunction* nj : newJunctions) {
nbCItem.first.edges.clear();
for (const std::string& ce : nbCItem.second) {
bool foundCE = false;
for (NBEdge* je : nj->getNBNode()->getEdges()) {
if (je->getID() == ce) {
foundCE = true;
nbCItem.first.edges.push_back(je);
break;
}
}
if (!foundCE) {
break;
}
}
if (nbCItem.first.edges.size() == nbCItem.second.size()) {
undoList->add(new GNEChange_Crossing(nj, nbCItem.first, true), true);
break;
}
}
}
const double resolution = OptionsCont::getOptions().getFloat("opendrive.curve-resolution") * 3;
for (int i = 0; i < (int)newJunctions.size(); i++) {
GNEJunction* from = newJunctions[(i + 1) % newJunctions.size()];
GNEJunction* to = newJunctions[i];
GNEEdge* newEdge = createEdge(from, to, nullptr, undoList);
const double angle1 = center.angleTo2D(from->getPositionInView());
const double angle2 = center.angleTo2D(to->getPositionInView());
const double angleDiff = fabs(GeomHelper::angleDiff(angle2, angle1));
int numSegments = MAX2(2, (int)ceil(angleDiff * radius / resolution));
PositionVector innerGeom;
for (int j = 1; j < numSegments; j++) {
const double angle = angle1 + lefthandSign * j * angleDiff / numSegments;
innerGeom.push_back(center + Position(cos(angle) * radius, sin(angle) * radius));
}
newEdge->setAttribute(SUMO_ATTR_SHAPE, toString(innerGeom), undoList);
if (templateEdge) {
GNEEdgeTemplate t(templateEdge);
newEdge->copyTemplate(&t, undoList);
}
}
undoList->end();
}
bool
GNENet::checkJunctionPosition(const Position& pos) {
for (auto& junction : myAttributeCarriers->getJunctions()) {
if (junction.second->getPositionInView() == pos) {
return false;
}
}
return true;
}
void
GNENet::saveNetwork() {
auto& neteditOptions = OptionsCont::getOptions();
auto& sumoOptions = myViewNet->getViewParent()->getGNEAppWindows()->getSumoOptions();
getApp()->beginWaitCursor();
neteditOptions.resetWritable();
neteditOptions.set("output-file", neteditOptions.getString("net-file"));
sumoOptions.resetWritable();
sumoOptions.set("net-file", neteditOptions.getString("net-file"));
computeAndUpdate(neteditOptions, false);
myNetBuilder->getTypeCont().clearTypes();
for (const auto& edgeType : myAttributeCarriers->getEdgeTypes()) {
myNetBuilder->getTypeCont().insertEdgeType(edgeType.first, edgeType.second);
for (int i = 0; i < (int)edgeType.second->getLaneTypes().size(); i++) {
myNetBuilder->getTypeCont().insertLaneType(edgeType.first, i,
edgeType.second->getLaneTypes().at(i)->speed,
edgeType.second->getLaneTypes().at(i)->permissions,
edgeType.second->getLaneTypes().at(i)->width,
edgeType.second->getLaneTypes().at(i)->attrs);
}
}
NWFrame::writeNetwork(neteditOptions, *myNetBuilder);
sumoOptions.resetWritable();
neteditOptions.resetDefault("output-file");
mySavingStatus->networkSaved();
getApp()->endWaitCursor();
}
void
GNENet::savePlain(const std::string& prefix) {
auto& neteditOptions = OptionsCont::getOptions();
computeAndUpdate(neteditOptions, false);
NWWriter_XML::writeNetwork(neteditOptions, prefix, *myNetBuilder);
}
void
GNENet::saveJoined(const std::string& filename) {
computeAndUpdate(OptionsCont::getOptions(), false);
NWWriter_XML::writeJoinedJunctions(filename, myNetBuilder->getNodeCont());
}
void
GNENet::setViewNet(GNEViewNet* viewNet) {
myViewNet = viewNet;
myAttributeCarriers->addDefaultVTypes();
for (const auto& edge : myAttributeCarriers->getEdges()) {
edge.second->updateGeometry();
}
myViewNet->update();
for (const auto& edge : myAttributeCarriers->getEdges()) {
edge.second->updateCenteringBoundary(true);
}
}
void
GNENet::addGLObjectIntoGrid(GNEAttributeCarrier* AC) {
if (AC->getTagProperty()->isPlacedInRTree() && !AC->inGrid()) {
myGrid.addAdditionalGLObject(AC->getGUIGlObject());
AC->setInGrid(true);
}
}
void
GNENet::removeGLObjectFromGrid(GNEAttributeCarrier* AC) {
if (AC->getTagProperty()->isPlacedInRTree() && AC->inGrid()) {
myGrid.removeAdditionalGLObject(AC->getGUIGlObject());
AC->setInGrid(false);
}
}
void
GNENet::computeNetwork(GNEApplicationWindow* window, bool force, bool volatileOptions) {
if (!myNeedRecompute) {
if (force) {
if (volatileOptions) {
window->setStatusBarText(TL("Forced computing junctions with volatile options ..."));
} else {
window->setStatusBarText(TL("Forced computing junctions ..."));
}
} else {
return;
}
} else {
if (volatileOptions) {
window->setStatusBarText(TL("Computing junctions with volatile options ..."));
} else {
window->setStatusBarText(TL("Computing junctions ..."));
}
}
getApp()->beginWaitCursor();
if (volatileOptions) {
for (const auto& edge : myAttributeCarriers->getEdges()) {
myEdgesAndNumberOfLanes[edge.second->getID()] = (int)edge.second->getChildLanes().size();
}
}
auto& neteditOptions = OptionsCont::getOptions();
computeAndUpdate(neteditOptions, volatileOptions);
if (volatileOptions && OptionsCont::getOptions().getString("additional-files").size() > 0) {
const auto additionalFiles = StringTokenizer(OptionsCont::getOptions().getString("additional-files"), ";").getVector();
for (const auto& file : additionalFiles) {
GNEGeneralHandler generalHandler(this, file, myViewNet->getViewParent()->getGNEAppWindows()->isUndoRedoAllowed());
if (!generalHandler.parse()) {
WRITE_ERROR(TL("Loading of additional file failed: ") + file);
} else {
WRITE_MESSAGE(TL("Loading of additional file successfully: ") + file);
}
}
}
if (volatileOptions && OptionsCont::getOptions().getString("route-files").size() > 0) {
GNEGeneralHandler generalHandler(this, OptionsCont::getOptions().getString("route-files"), false);
if (!generalHandler.parse()) {
WRITE_ERROR(TL("Loading of route file failed: ") + OptionsCont::getOptions().getString("route-files"));
} else {
WRITE_MESSAGE(TL("Loading of route file successfully: ") + OptionsCont::getOptions().getString("route-files"));
}
}
if (volatileOptions && OptionsCont::getOptions().getString("data-files").size() > 0) {
GNEDataHandler dataHandler(this, OptionsCont::getOptions().getString("data-files"), false);
if (!dataHandler.parse()) {
WRITE_ERROR(TL("Loading of data file failed: ") + OptionsCont::getOptions().getString("data-files"));
} else {
WRITE_MESSAGE(TL("Loading of data file successfully: ") + OptionsCont::getOptions().getString("data-files"));
}
}
if (volatileOptions && OptionsCont::getOptions().getString("meandata-files").size() > 0) {
GNEGeneralHandler generalHandler(this, OptionsCont::getOptions().getString("meandata-files"), false);
if (!generalHandler.parse()) {
WRITE_ERROR(TL("Loading of meandata file failed: ") + OptionsCont::getOptions().getString("meandata-files"));
} else {
WRITE_MESSAGE(TL("Loading of meandata file successfully: ") + OptionsCont::getOptions().getString("meandata-files"));
}
}
myEdgesAndNumberOfLanes.clear();
getApp()->endWaitCursor();
window->setStatusBarText(TL("Finished computing junctions."));
}
void
GNENet::computeDemandElements(GNEApplicationWindow* window) {
window->setStatusBarText(TL("Computing demand elements ..."));
if (!myViewNet->getEditModes().isCurrentSupermodeDemand() &&
!myDemandPathManager->getPathCalculator()->isPathCalculatorUpdated()) {
myDemandPathManager->getPathCalculator()->updatePathCalculator();
}
myDemandPathManager->clearSegments();
for (const auto& demandElements : myAttributeCarriers->getDemandElements()) {
for (const auto& demandElement : demandElements.second) {
demandElement.second->computePathElement();
}
}
window->setStatusBarText(TL("Finished computing demand elements."));
}
void
GNENet::computeDataElements(GNEApplicationWindow* window) {
window->setStatusBarText(TL("Computing data elements ..."));
for (const auto& genericDataTag : myAttributeCarriers->getGenericDatas()) {
for (const auto& genericData : genericDataTag.second) {
genericData.second->computePathElement();
}
}
window->setStatusBarText(TL("Finished computing data elements."));
}
void
GNENet::computeJunction(GNEJunction* junction) {
auto& neteditOptions = OptionsCont::getOptions();
NBTrafficLightLogicCont& tllCont = getTLLogicCont();
const std::set<NBTrafficLightDefinition*> tlsDefs = junction->getNBNode()->getControllingTLS();
for (auto it : tlsDefs) {
it->setParticipantsInformation();
it->setTLControllingInformation();
tllCont.computeSingleLogic(neteditOptions, it);
}
}
void
GNENet::requireRecompute() {
myNeedRecompute = true;
}
bool
GNENet::isNetRecomputed() const {
return !myNeedRecompute;
}
FXApp*
GNENet::getApp() {
return myViewNet->getApp();
}
NBNetBuilder*
GNENet::getNetBuilder() const {
return myNetBuilder;
}
bool
GNENet::joinSelectedJunctions(GNEUndoList* undoList) {
const auto selectedJunctions = myAttributeCarriers->getSelectedJunctions();
if (selectedJunctions.size() < 2) {
return false;
}
EdgeVector allIncoming;
EdgeVector allOutgoing;
std::set<NBNode*, ComparatorIdLess> cluster;
for (const auto& selectedJunction : selectedJunctions) {
cluster.insert(selectedJunction->getNBNode());
const EdgeVector& incoming = selectedJunction->getNBNode()->getIncomingEdges();
allIncoming.insert(allIncoming.end(), incoming.begin(), incoming.end());
const EdgeVector& outgoing = selectedJunction->getNBNode()->getOutgoingEdges();
allOutgoing.insert(allOutgoing.end(), outgoing.begin(), outgoing.end());
}
Position pos;
Position oldPos;
bool setTL = false;
std::string id = "cluster";
TrafficLightType type;
SumoXMLNodeType nodeType = SumoXMLNodeType::UNKNOWN;
myNetBuilder->getNodeCont().analyzeCluster(cluster, id, pos, setTL, type, nodeType);
oldPos = pos;
for (const auto& junction : myAttributeCarriers->getJunctions()) {
if ((junction.second->getPositionInView() == pos) && (cluster.find(junction.second->getNBNode()) == cluster.end())) {
const auto questionDialog = GNEQuestionBasicDialog(myViewNet->getViewParent()->getGNEAppWindows(), GNEDialog::Buttons::YES_NO,
TL("Position of joined junction"),
TL("There is another unselected junction in the same position of joined junction."),
TL("It will be joined with the other selected junctions. Continue?"));
if (questionDialog.getResult() == GNEDialog::Result::ACCEPT) {
junction.second->setAttribute(GNE_ATTR_SELECTED, "true", undoList);
return joinSelectedJunctions(undoList);
} else {
return false;
}
}
}
while (!checkJunctionPosition(pos)) {
pos.setx(pos.x() + 0.1);
pos.sety(pos.y() + 0.1);
}
undoList->begin(GUIIcon::JUNCTION, "Join selected " + toString(SUMO_TAG_JUNCTION) + "s");
GNEJunction* joined = createJunction(pos, undoList);
joined->setAttribute(SUMO_ATTR_ID, id, undoList);
joined->setAttribute(SUMO_ATTR_TYPE, toString(nodeType), undoList);
if (setTL) {
joined->setAttribute(SUMO_ATTR_TLTYPE, toString(type), undoList);
}
GNEChange_RegisterJoin::registerJoin(cluster, myNetBuilder->getNodeCont(), undoList);
std::vector<NBNode::Crossing> oldCrossings;
for (const auto& selectedJunction : selectedJunctions) {
const auto crossings = selectedJunction->getGNECrossings();
for (auto crossing : crossings) {
deleteCrossing(crossing, undoList);
}
}
for (const auto& selectedJunction : selectedJunctions) {
selectedJunction->setLogicValid(false, undoList);
}
for (const auto& incomingEdge : allIncoming) {
if (std::find(allOutgoing.begin(), allOutgoing.end(), incomingEdge) == allOutgoing.end()) {
GNEChange_Attribute::changeAttribute(myAttributeCarriers->getEdges().at(incomingEdge->getID()), SUMO_ATTR_TO, joined->getID(), undoList);
}
}
EdgeSet edgesWithin;
for (const auto& outgoingEdge : allOutgoing) {
GNEEdge* edge = myAttributeCarriers->getEdges().at(outgoingEdge->getID());
if (edge->getToJunction() == joined) {
edgesWithin.insert(outgoingEdge);
deleteEdge(edge, undoList, false);
} else {
GNEChange_Attribute::changeAttribute(myAttributeCarriers->getEdges().at(outgoingEdge->getID()), SUMO_ATTR_FROM, joined->getID(), undoList);
}
}
for (const auto& nbc : oldCrossings) {
bool keep = true;
for (NBEdge* e : nbc.edges) {
if (edgesWithin.count(e) != 0) {
keep = false;
break;
}
};
if (keep) {
undoList->add(new GNEChange_Crossing(joined, nbc.edges, nbc.width,
nbc.priority || joined->getNBNode()->isTLControlled(),
nbc.customTLIndex, nbc.customTLIndex2, nbc.customShape,
false, true), true);
}
}
for (const auto& selectedJunction : selectedJunctions) {
deleteJunction(selectedJunction, undoList);
}
if (pos != oldPos) {
joined->setAttribute(SUMO_ATTR_POSITION, toString(oldPos), undoList);
}
undoList->end();
return true;
}
bool
GNENet::cleanInvalidCrossings(GNEUndoList* undoList) {
std::vector<GNECrossing*> myNetCrossings;
for (const auto& junction : myAttributeCarriers->getJunctions()) {
myNetCrossings.reserve(myNetCrossings.size() + junction.second->getGNECrossings().size());
myNetCrossings.insert(myNetCrossings.end(), junction.second->getGNECrossings().begin(), junction.second->getGNECrossings().end());
}
std::vector<GNECrossing*> myInvalidCrossings;
for (auto i = myNetCrossings.begin(); i != myNetCrossings.end(); i++) {
if (!(*i)->getNBCrossing()->valid) {
myInvalidCrossings.push_back(*i);
}
}
if (myInvalidCrossings.empty()) {
GNEWarningBasicDialog(myViewNet->getViewParent()->getGNEAppWindows(),
TL("Clear crossings"),
TL("There are no invalid crossings to remove."));
} else {
std::string plural = myInvalidCrossings.size() == 1 ? ("") : ("s");
const auto questionDialog = GNEQuestionBasicDialog(myViewNet->getViewParent()->getGNEAppWindows(),
GNEDialog::Buttons::YES_NO, TL("Clear crossings"),
TL("Crossings will be cleared. Continue?"));
if (questionDialog.getResult() == GNEDialog::Result::ACCEPT) {
undoList->begin(GUIIcon::MODEDELETE, TL("clear crossings"));
for (const auto& crossing : myInvalidCrossings) {
deleteCrossing(crossing, undoList);
}
undoList->end();
} else {
return false;
}
}
return true;
}
void
GNENet::removeSolitaryJunctions(GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("clear junctions"));
std::vector<GNEJunction*> toRemove;
for (auto& junction : myAttributeCarriers->getJunctions()) {
if (junction.second->getNBNode()->getEdges().size() == 0) {
toRemove.push_back(junction.second);
}
}
for (auto junction : toRemove) {
deleteJunction(junction, undoList);
}
undoList->end();
}
void
GNENet::cleanUnusedRoutes(GNEUndoList* undoList) {
std::vector<GNEDemandElement*> routesWithoutChildren;
routesWithoutChildren.reserve(myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE).size());
for (const auto& route : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE)) {
if (route.second->getChildDemandElements().empty()) {
routesWithoutChildren.push_back(route.second);
}
}
if (routesWithoutChildren.size() > 0) {
undoList->begin(GUIIcon::MODEDELETE, TL("clear unused routes"));
for (const auto& i : routesWithoutChildren) {
undoList->add(new GNEChange_DemandElement(i, false), true);
}
undoList->end();
}
}
void
GNENet::joinRoutes(GNEUndoList* undoList) {
std::set<std::pair<std::string, GNEDemandElement*> > mySortedRoutes;
for (const auto& route : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE)) {
bool hasStops = false;
for (const auto& stop : route.second->getChildDemandElements()) {
if (stop->getTagProperty()->isVehicleStop()) {
hasStops = true;
}
}
if (!hasStops) {
mySortedRoutes.insert(std::make_pair(GNEAttributeCarrier::parseIDs(route.second->getParentEdges()), route.second));
}
}
std::vector<std::vector<GNEDemandElement*> > routesToMerge;
auto index = mySortedRoutes.begin();
for (auto i = mySortedRoutes.begin(); i != mySortedRoutes.end(); i++) {
if (routesToMerge.empty()) {
routesToMerge.push_back({i->second});
} else {
if (index->first == i->first) {
routesToMerge.back().push_back(i->second);
} else {
routesToMerge.push_back({i->second});
index = i;
}
}
}
bool thereIsRoutesToMerge = false;
for (const auto& i : routesToMerge) {
if (i.size() > 1) {
thereIsRoutesToMerge = true;
}
}
if (thereIsRoutesToMerge) {
undoList->begin(GUIIcon::ROUTE, TL("merge routes"));
for (const auto& routes : routesToMerge) {
if (routes.size() > 1) {
for (int i = 1; i < (int)routes.size(); i++) {
while (routes.at(i)->getChildDemandElements().size() > 0) {
routes.at(i)->getChildDemandElements().front()->setAttribute(SUMO_ATTR_ROUTE, routes.at(0)->getID(), undoList);
}
undoList->add(new GNEChange_DemandElement(routes.at(i), false), true);
}
}
}
undoList->end();
}
}
void
GNENet::adjustPersonPlans(GNEUndoList* undoList) {
std::map<GNEDemandElement*, std::string> personPlanMap;
for (const auto& persontag : {
SUMO_TAG_PERSON, SUMO_TAG_PERSONFLOW
}) {
for (const auto& person : myAttributeCarriers->getDemandElements().at(persontag)) {
if (person.second->getChildDemandElements().size() > 0) {
GNEDemandElement* personPlan = person.second->getChildDemandElements().front();
while (personPlan) {
if (personPlan->getTagProperty()->getTag() == GNE_TAG_STOPPERSON_EDGE) {
GNEDemandElement* previousPersonPlan = person.second->getPreviousChildDemandElement(personPlan);
if (previousPersonPlan && previousPersonPlan->getTagProperty()->hasAttribute(SUMO_ATTR_ARRIVALPOS) &&
(previousPersonPlan->getAttribute(SUMO_ATTR_ARRIVALPOS) != personPlan->getAttribute(SUMO_ATTR_ENDPOS))) {
personPlanMap[previousPersonPlan] = personPlan->getAttribute(SUMO_ATTR_ENDPOS);
}
}
personPlan = person.second->getNextChildDemandElement(personPlan);
}
}
}
}
if (personPlanMap.size() > 0) {
undoList->begin(GUIIcon::MODEPERSONPLAN, TL("adjust person plans"));
for (const auto& personPlan : personPlanMap) {
personPlan.first->setAttribute(SUMO_ATTR_ARRIVALPOS, personPlan.second, undoList);
}
undoList->end();
}
}
void
GNENet::cleanInvalidDemandElements(GNEUndoList* undoList) {
std::vector<GNEDemandElement*> invalidDemandElements;
invalidDemandElements.reserve(myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE).size() +
myAttributeCarriers->getDemandElements().at(SUMO_TAG_FLOW).size() +
myAttributeCarriers->getDemandElements().at(SUMO_TAG_TRIP).size());
for (const auto& route : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE)) {
if (route.second->isDemandElementValid() != GNEDemandElement::Problem::OK) {
invalidDemandElements.push_back(route.second);
}
}
for (const auto& flow : myAttributeCarriers->getDemandElements().at(SUMO_TAG_FLOW)) {
if (flow.second->isDemandElementValid() != GNEDemandElement::Problem::OK) {
invalidDemandElements.push_back(flow.second);
}
}
for (const auto& trip : myAttributeCarriers->getDemandElements().at(SUMO_TAG_TRIP)) {
if (trip.second->isDemandElementValid() != GNEDemandElement::Problem::OK) {
invalidDemandElements.push_back(trip.second);
}
}
if (invalidDemandElements.size() > 0) {
undoList->begin(GUIIcon::MODEDELETE, TL("remove invalid demand elements"));
for (const auto& invalidDemandElement : invalidDemandElements) {
undoList->add(new GNEChange_DemandElement(invalidDemandElement, false), true);
}
undoList->end();
}
}
void
GNENet::replaceJunctionByGeometry(GNEJunction* junction, GNEUndoList* undoList) {
if (junction->getNBNode()->checkIsRemovable()) {
undoList->begin(junction, TL("replace junction by geometry"));
std::vector<std::pair<NBEdge*, NBEdge*> > edgesToJoin = junction->getNBNode()->getEdgesToJoin();
clearJunctionConnections(junction, undoList);
for (auto edgePair : edgesToJoin) {
GNEEdge* begin = myAttributeCarriers->getEdges().at(edgePair.first->getID());
GNEEdge* continuation = myAttributeCarriers->getEdges().at(edgePair.second->getID());
std::vector<NBEdge::Connection> connections = begin->getNBEdge()->getConnections();
for (auto con : connections) {
undoList->add(new GNEChange_Connection(begin, con, false, false), true);
}
PositionVector newShape = begin->getNBEdge()->getInnerGeometry();
newShape.push_back(junction->getNBNode()->getPosition());
replaceIncomingEdge(continuation, begin, undoList);
newShape.append(continuation->getNBEdge()->getInnerGeometry());
begin->setAttribute(GNE_ATTR_SHAPE_END, "", undoList);
begin->setAttribute(SUMO_ATTR_ENDOFFSET, continuation->getAttribute(SUMO_ATTR_ENDOFFSET), undoList);
begin->setAttribute(SUMO_ATTR_SHAPE, toString(newShape), undoList);
begin->getNBEdge()->resetNodeBorder(begin->getNBEdge()->getToNode());
if (begin->getNBEdge()->hasLoadedLength() || continuation->getNBEdge()->hasLoadedLength()) {
begin->setAttribute(SUMO_ATTR_LENGTH, toString(begin->getNBEdge()->getLoadedLength() + continuation->getNBEdge()->getLoadedLength()), undoList);
}
}
deleteJunction(junction, undoList);
undoList->end();
} else {
throw ProcessError(TL("Junction isn't removable"));
}
}
void
GNENet::splitJunction(GNEJunction* junction, bool reconnect, GNEUndoList* undoList) {
std::vector<std::pair<Position, std::string> > endpoints = junction->getNBNode()->getEndPoints();
if (endpoints.size() < 2) {
return;
}
undoList->begin(junction, TL("split junction"));
std::map<std::pair<std::string, GNEEdge*>, std::vector<NBEdge::Connection>> straightConnections;
for (GNEEdge* e : junction->getGNEIncomingEdges()) {
for (const auto& c : e->getNBEdge()->getConnections()) {
if (c.fromLane >= 0 && junction->getNBNode()->getDirection(e->getNBEdge(), c.toEdge) == LinkDirection::STRAIGHT) {
straightConnections[std::make_pair(e->getID(), e)].push_back(c);
}
};
}
junction->setLogicValid(false, undoList);
for (const auto& pair : endpoints) {
const Position& pos = pair.first;
const std::string& origID = pair.second;
GNEJunction* newJunction = createJunction(pos, undoList);
std::string newID = origID != "" ? origID : newJunction->getID();
const std::vector<GNEEdge*> incoming = junction->getGNEIncomingEdges();
const std::vector<GNEEdge*> outgoing = junction->getGNEOutgoingEdges();
for (GNEEdge* e : incoming) {
if (e->getNBEdge()->getGeometry().back().almostSame(pos) || e->getNBEdge()->getParameter("origTo") == newID) {
GNEChange_Attribute::changeAttribute(e, SUMO_ATTR_TO, newJunction->getID(), undoList);
}
}
for (GNEEdge* e : outgoing) {
if (e->getNBEdge()->getGeometry().front().almostSame(pos) || e->getNBEdge()->getParameter("origFrom") == newID) {
GNEChange_Attribute::changeAttribute(e, SUMO_ATTR_FROM, newJunction->getID(), undoList);
}
}
if (newID != newJunction->getID()) {
if (newJunction->isValid(SUMO_ATTR_ID, newID)) {
GNEChange_Attribute::changeAttribute(newJunction, SUMO_ATTR_ID, newID, undoList);
} else {
WRITE_WARNINGF(TL("Could not rename split node to '%'"), newID);
}
}
}
if (reconnect) {
for (const auto& item : straightConnections) {
GNEEdge* in = item.first.second;
std::map<std::pair<std::string, NBEdge*>, GNEEdge*> newEdges;
for (auto& c : item.second) {
GNEEdge* out = myAttributeCarriers->retrieveEdge(c.toEdge->getID());
GNEEdge* newEdge = nullptr;
if (in->getToJunction() == out->getFromJunction()) {
continue;
}
if (newEdges.count(std::make_pair(c.toEdge->getID(), c.toEdge)) == 0) {
newEdge = createEdge(in->getToJunction(), out->getFromJunction(), in, undoList);
if (newEdge) {
newEdges[std::make_pair(c.toEdge->getID(), c.toEdge)] = newEdge;
newEdge->setAttribute(SUMO_ATTR_NUMLANES, "1", undoList);
}
} else {
newEdge = newEdges[std::make_pair(c.toEdge->getID(), c.toEdge)];
duplicateLane(newEdge->getChildLanes().back(), undoList, true);
}
if (newEdge) {
newEdge->getChildLanes().back()->setAttribute(SUMO_ATTR_ALLOW,
in->getChildLanes()[c.fromLane]-> getAttribute(SUMO_ATTR_ALLOW), undoList);
}
}
}
}
deleteJunction(junction, undoList);
undoList->end();
}
void
GNENet::clearJunctionConnections(GNEJunction* junction, GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("clear junction connections"));
std::vector<GNEConnection*> connections = junction->getGNEConnections();
for (auto i : connections) {
deleteConnection(i, undoList);
}
undoList->end();
}
void
GNENet::resetJunctionConnections(GNEJunction* junction, GNEUndoList* undoList) {
undoList->begin(junction, TL("reset junction connections"));
clearJunctionConnections(junction, undoList);
junction->setLogicValid(false, undoList);
undoList->end();
}
void
GNENet::clearAdditionalElements(GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("clear additional elements"));
for (const auto& additionalMap : myAttributeCarriers->getAdditionals()) {
while (additionalMap.second.size() > 0) {
deleteAdditional(additionalMap.second.begin()->second, undoList);
}
}
undoList->end();
}
void
GNENet::clearDemandElements(GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("clear demand elements"));
for (const auto& demandElementsMap : myAttributeCarriers->getDemandElements()) {
if (demandElementsMap.first != SUMO_TAG_VTYPE) {
while (demandElementsMap.second.size() > 0) {
deleteDemandElement(demandElementsMap.second.begin()->second, undoList);
}
}
}
const std::unordered_map<const GUIGlObject*, GNEDemandElement*> types = myAttributeCarriers->getDemandElements().at(SUMO_TAG_VTYPE);
for (const auto& type : types) {
if (type.second->getAttribute(GNE_ATTR_DEFAULT_VTYPE) == GNEAttributeCarrier::FALSE_STR) {
deleteDemandElement(type.second, undoList);
}
}
undoList->end();
}
void
GNENet::clearDataElements(GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("clear data elements"));
while (myAttributeCarriers->getDataSets().size() > 0) {
deleteDataSet(myAttributeCarriers->getDataSets().begin()->second, undoList);
}
undoList->end();
}
void
GNENet::clearMeanDataElements(GNEUndoList* undoList) {
undoList->begin(GUIIcon::MODEDELETE, TL("clear meanData elements"));
for (const auto& meanDataMap : myAttributeCarriers->getMeanDatas()) {
while (meanDataMap.second.size() > 0) {
deleteMeanData(meanDataMap.second.begin()->second, undoList);
}
}
undoList->end();
}
void
GNENet::changeEdgeEndpoints(GNEEdge* edge, const std::string& newSource, const std::string& newDest) {
NBNode* from = myAttributeCarriers->retrieveJunction(newSource)->getNBNode();
NBNode* to = myAttributeCarriers->retrieveJunction(newDest)->getNBNode();
edge->getNBEdge()->reinitNodes(from, to);
requireRecompute();
}
GNEViewNet*
GNENet::getViewNet() const {
return myViewNet;
}
NBTrafficLightLogicCont&
GNENet::getTLLogicCont() {
return myNetBuilder->getTLLogicCont();
}
NBEdgeCont&
GNENet::getEdgeCont() {
return myNetBuilder->getEdgeCont();
}
void
GNENet::addExplicitTurnaround(std::string id) {
myExplicitTurnarounds.insert(id);
}
void
GNENet::removeExplicitTurnaround(std::string id) {
myExplicitTurnarounds.erase(id);
}
bool
GNENet::saveAdditionals() {
std::vector<GNEAdditional*> invalidAdditionals;
for (const auto& additionalPair : myAttributeCarriers->getAdditionals()) {
for (const auto& addditional : additionalPair.second) {
if (!addditional.second->isAdditionalValid()) {
invalidAdditionals.push_back(addditional.second);
}
}
}
if (invalidAdditionals.size() > 0) {
const auto fixAdditionalElements = GNEFixAdditionalElementsDialog(myViewNet->getViewParent()->getGNEAppWindows(),
invalidAdditionals);
if (fixAdditionalElements.getResult() != GNEDialog::Result::ACCEPT) {
return false;
}
}
saveAdditionalsConfirmed();
return true;
}
bool
GNENet::saveJuPedSimElements(const std::unordered_set<const GNEAttributeCarrier*>& ACs, const std::string& file) {
OutputDevice& device = OutputDevice::getDevice(file);
device.writeXMLHeader("additional", "additional_file.xsd", EMPTY_HEADER, false);
writeJuPedSimComment(device, ACs);
writeAdditionalByType(device, ACs, {GNE_TAG_JPS_WALKABLEAREA});
writeAdditionalByType(device, ACs, {GNE_TAG_JPS_OBSTACLE});
device.close();
myViewNet->setFocus();
return true;
}
bool
GNENet::saveDemandElements() {
computeDemandElements(myViewNet->getViewParent()->getGNEAppWindows());
std::vector<GNEDemandElement*> invalidSingleLaneDemandElements;
for (const auto& demandElementSet : myAttributeCarriers->getDemandElements()) {
for (const auto& demandElement : demandElementSet.second) {
demandElement.second->computePathElement();
if (demandElement.second->isDemandElementValid() != GNEDemandElement::Problem::OK) {
invalidSingleLaneDemandElements.push_back(demandElement.second);
}
}
}
if (invalidSingleLaneDemandElements.size() > 0) {
const auto fixDemandElement = GNEFixDemandElementsDialog(myViewNet->getViewParent()->getGNEAppWindows(),
invalidSingleLaneDemandElements);
if (fixDemandElement.getResult() != GNEDialog::Result::ACCEPT) {
return false;
}
}
saveDemandElementsConfirmed();
return true;
}
bool
GNENet::saveDataElements() {
computeDataElements(myViewNet->getViewParent()->getGNEAppWindows());
saveDataElementsConfirmed();
myViewNet->setFocus();
return true;
}
double
GNENet::getDataSetIntervalMinimumBegin() const {
double minimumBegin = 0;
if (myAttributeCarriers->getDataIntervals().size() > 0) {
minimumBegin = myAttributeCarriers->getDataIntervals().begin()->second->getAttributeDouble(SUMO_ATTR_BEGIN);
}
for (const auto& interval : myAttributeCarriers->getDataIntervals()) {
if (interval.second->getAttributeDouble(SUMO_ATTR_BEGIN) < minimumBegin) {
minimumBegin = interval.second->getAttributeDouble(SUMO_ATTR_BEGIN);
}
}
return minimumBegin;
}
double
GNENet::getDataSetIntervalMaximumEnd() const {
double maximumEnd = 0;
if (myAttributeCarriers->getDataIntervals().size() > 0) {
maximumEnd = myAttributeCarriers->getDataIntervals().begin()->second->getAttributeDouble(SUMO_ATTR_END);
}
for (const auto& interval : myAttributeCarriers->getDataIntervals()) {
if (interval.second->getAttributeDouble(SUMO_ATTR_END) > maximumEnd) {
maximumEnd = interval.second->getAttributeDouble(SUMO_ATTR_END);
}
}
return maximumEnd;
}
bool
GNENet::saveMeanDatas() {
saveMeanDatasConfirmed();
myViewNet->setFocus();
return true;
}
void
GNENet::saveAdditionalsConfirmed() {
getApp()->beginWaitCursor();
const auto additionalByFilenames = mySavingFilesHandler->getAdditionalsByFilename();
mySavingFilesHandler->updateNeteditConfig();
for (const auto& additionalsByFilename : additionalByFilenames) {
OutputDevice& device = OutputDevice::getDevice(additionalsByFilename.first);
device.writeXMLHeader("additional", "additional_file.xsd", EMPTY_HEADER, false);
writeVTypeComment(device, additionalsByFilename.second, true);
writeVTypes(device, additionalsByFilename.second, true);
writeRouteComment(device, additionalsByFilename.second, true);
writeRoutes(device, additionalsByFilename.second, true);
writeRouteProbeComment(device, additionalsByFilename.second);
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_ROUTEPROBE});
writeCalibratorComment(device, additionalsByFilename.second);
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_CALIBRATOR, GNE_TAG_CALIBRATOR_LANE});
writeStoppingPlaceComment(device, additionalsByFilename.second);
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_BUS_STOP});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_TRAIN_STOP});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_CONTAINER_STOP});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_PARKING_AREA});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_CHARGING_STATION});
writeDetectorComment(device, additionalsByFilename.second);
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_INDUCTION_LOOP});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_INSTANT_INDUCTION_LOOP});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_LANE_AREA_DETECTOR, GNE_TAG_MULTI_LANE_AREA_DETECTOR});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_ENTRY_EXIT_DETECTOR});
writeOtherAdditionalsComment(device, additionalsByFilename.second);
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_REROUTER});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_VSS});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_VAPORIZER});
writeShapesComment(device, additionalsByFilename.second);
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_POLY});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_POI, GNE_TAG_POILANE, GNE_TAG_POIGEO});
writeTAZComment(device, additionalsByFilename.second);
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_TAZ});
writeWireComment(device, additionalsByFilename.second);
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_TRACTION_SUBSTATION});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_OVERHEAD_WIRE_SECTION});
writeAdditionalByType(device, additionalsByFilename.second, {SUMO_TAG_OVERHEAD_WIRE_CLAMP});
writeJuPedSimComment(device, additionalsByFilename.second);
writeAdditionalByType(device, additionalsByFilename.second, {GNE_TAG_JPS_WALKABLEAREA});
writeAdditionalByType(device, additionalsByFilename.second, {GNE_TAG_JPS_OBSTACLE});
device.close();
}
mySavingStatus->additionalsSaved();
getApp()->endWaitCursor();
}
void
GNENet::saveDemandElementsConfirmed() {
getApp()->beginWaitCursor();
const auto demandByFilenames = mySavingFilesHandler->getDemandsByFilename();
mySavingFilesHandler->updateNeteditConfig();
for (const auto& demandByFilename : demandByFilenames) {
OutputDevice& device = OutputDevice::getDevice(demandByFilename.first);
device.writeXMLHeader("routes", "routes_file.xsd", EMPTY_HEADER, false);
writeVTypeComment(device, demandByFilename.second, false);
writeVTypes(device, demandByFilename.second, false);
writeVTypeDistributions(device, demandByFilename.second);
writeRouteComment(device, demandByFilename.second, false);
writeRoutes(device, demandByFilename.second, false);
writeRouteDistributions(device, demandByFilename.second);
std::map<double, std::map<std::pair<SumoXMLTag, std::string>, GNEDemandElement*> > vehiclesSortedByDepart;
for (const auto& demandElementTag : myAttributeCarriers->getDemandElements()) {
for (const auto& demandElement : demandElementTag.second) {
if (demandElement.second->getTagProperty()->isVehicle() || demandElement.second->getTagProperty()->isPerson() || demandElement.second->getTagProperty()->isContainer()) {
vehiclesSortedByDepart[demandElement.second->getAttributeDouble(SUMO_ATTR_DEPART)][std::make_pair(demandElement.second->getTagProperty()->getTag(), demandElement.second->getID())] = demandElement.second;
}
}
}
if (vehiclesSortedByDepart.size() > 0) {
device << (" <!-- Vehicles, persons and containers (sorted by depart) -->\n");
for (const auto& vehicleTag : vehiclesSortedByDepart) {
for (const auto& vehicle : vehicleTag.second) {
if (demandByFilename.second.count(vehicle.second) > 0) {
vehicle.second->writeDemandElement(device);
}
}
}
}
device.close();
}
mySavingStatus->demandElementsSaved();
getApp()->endWaitCursor();
}
void
GNENet::saveDataElementsConfirmed() {
getApp()->beginWaitCursor();
const auto dataByFilenames = mySavingFilesHandler->getDatasByFilename();
mySavingFilesHandler->updateNeteditConfig();
for (const auto& dataByFilename : dataByFilenames) {
OutputDevice& device = OutputDevice::getDevice(dataByFilename.first);
device.writeXMLHeader("data", "datamode_file.xsd", EMPTY_HEADER, false);
for (const auto& dataSet : myAttributeCarriers->getDataSets()) {
if (dataByFilename.second.count(dataSet.second) > 0) {
dataSet.second->writeDataSet(device);
}
}
device.close();
}
mySavingStatus->dataElementsSaved();
getApp()->endWaitCursor();
}
void
GNENet::saveMeanDatasConfirmed() {
getApp()->beginWaitCursor();
const auto meanDataByFilenames = mySavingFilesHandler->getMeanDatasByFilename();
mySavingFilesHandler->updateNeteditConfig();
for (const auto& meanDataByFilename : meanDataByFilenames) {
OutputDevice& device = OutputDevice::getDevice(meanDataByFilename.first);
device.writeXMLHeader("additional", "additional_file.xsd", EMPTY_HEADER, false);
writeMeanDataEdgeComment(device);
writeMeanDatas(device, meanDataByFilename.second, SUMO_TAG_MEANDATA_EDGE);
writeMeanDataLaneComment(device);
writeMeanDatas(device, meanDataByFilename.second, SUMO_TAG_MEANDATA_LANE);
device.close();
}
mySavingStatus->meanDatasSaved();
getApp()->endWaitCursor();
}
void
GNENet::writeAdditionalByType(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs,
const std::vector<SumoXMLTag> tags) const {
std::map<std::string, std::vector<GNEAdditional*> > sortedAdditionals;
for (const auto& tag : tags) {
for (const auto& additional : myAttributeCarriers->getAdditionals().at(tag)) {
if ((tag == SUMO_TAG_VAPORIZER) || (sortedAdditionals.count(additional.second->getID()) == 0)) {
sortedAdditionals[additional.second->getID()].push_back(additional.second);
} else {
throw ProcessError(TL("Duplicated ID"));
}
}
}
for (const auto& additionalVector : sortedAdditionals) {
for (const auto& additional : additionalVector.second) {
if (ACs.count(additional) > 0) {
additional->writeAdditional(device);
}
}
}
}
void
GNENet::writeDemandByType(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, SumoXMLTag tag) const {
std::map<std::string, GNEDemandElement*> sortedDemandElements;
for (const auto& demandElement : myAttributeCarriers->getDemandElements().at(tag)) {
if (ACs.count(demandElement.second) > 0) {
sortedDemandElements[demandElement.second->getID()] = demandElement.second;
}
}
for (const auto& demandElement : sortedDemandElements) {
demandElement.second->writeDemandElement(device);
}
}
void
GNENet::writeRouteDistributions(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
std::map<std::string, GNEDemandElement*> sortedElements;
for (const auto& routeDistribution : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE_DISTRIBUTION)) {
if (ACs.count(routeDistribution.second) > 0) {
sortedElements[routeDistribution.second->getID()] = routeDistribution.second;
}
}
for (const auto& element : sortedElements) {
element.second->writeDemandElement(device);
}
sortedElements.clear();
}
void
GNENet::writeRoutes(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, const bool additionalFile) const {
std::map<std::string, GNEDemandElement*> sortedRoutes;
for (const auto& route : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE)) {
if (ACs.count(route.second) > 0) {
int numRefs = 0;
for (const auto vTypeChild : route.second->getChildDemandElements()) {
if (vTypeChild->getTagProperty()->getTag() == GNE_TAG_ROUTEREF) {
numRefs++;
}
}
if (numRefs != 1) {
if ((additionalFile && (route.second->getChildAdditionals().size() > 0)) ||
(!additionalFile && (route.second->getChildAdditionals().size() == 0))) {
sortedRoutes[route.second->getID()] = route.second;
}
}
}
}
for (const auto& route : sortedRoutes) {
route.second->writeDemandElement(device);
}
}
void
GNENet::writeVTypeDistributions(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
std::map<std::string, GNEDemandElement*> sortedElements;
for (const auto& vTypeDistribution : myAttributeCarriers->getDemandElements().at(SUMO_TAG_VTYPE_DISTRIBUTION)) {
if (ACs.count(vTypeDistribution.second) > 0) {
sortedElements[vTypeDistribution.second->getID()] = vTypeDistribution.second;
}
}
for (const auto& element : sortedElements) {
element.second->writeDemandElement(device);
}
sortedElements.clear();
}
void
GNENet::writeVTypes(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, const bool additionalFile) const {
std::map<std::string, GNEDemandElement*> sortedVTypes;
for (const auto& vType : myAttributeCarriers->getDemandElements().at(SUMO_TAG_VTYPE)) {
if (ACs.count(vType.second) > 0) {
int numRefs = 0;
for (const auto vTypeChild : vType.second->getChildDemandElements()) {
if (vTypeChild->getTagProperty()->getTag() == GNE_TAG_VTYPEREF) {
numRefs++;
}
}
if (numRefs != 1) {
if ((additionalFile && (vType.second->getChildAdditionals().size() > 0)) ||
(!additionalFile && (vType.second->getChildAdditionals().size() == 0))) {
sortedVTypes[vType.second->getID()] = vType.second;
}
}
}
}
for (const auto& vType : sortedVTypes) {
vType.second->writeDemandElement(device);
}
}
void
GNENet::writeMeanDatas(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, SumoXMLTag tag) const {
std::map<std::string, GNEMeanData*> sortedMeanDatas;
for (const auto& meanData : myAttributeCarriers->getMeanDatas().at(tag)) {
if (ACs.count(meanData.second) > 0) {
if (sortedMeanDatas.count(meanData.second->getID()) == 0) {
sortedMeanDatas[meanData.second->getID()] = meanData.second;
} else {
throw ProcessError(TL("Duplicated ID"));
}
}
}
for (const auto& additional : sortedMeanDatas) {
additional.second->writeMeanData(device);
}
}
bool
GNENet::writeVTypeComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, const bool additionalFile) const {
for (const auto& vType : myAttributeCarriers->getDemandElements().at(SUMO_TAG_VTYPE)) {
const bool defaultVType = GNEAttributeCarrier::parse<bool>(vType.second->getAttribute(GNE_ATTR_DEFAULT_VTYPE));
const bool defaultVTypeModified = GNEAttributeCarrier::parse<bool>(vType.second->getAttribute(GNE_ATTR_DEFAULT_VTYPE_MODIFIED));
if ((vType.second->getParentDemandElements().size() == 0) && (!defaultVType || (defaultVType && defaultVTypeModified))) {
if (ACs.count(vType.second) > 0) {
if (additionalFile && (vType.second->getChildAdditionals().size() != 0)) {
device << (" <!-- VTypes (used in calibratorFlows) -->\n");
return true;
} else if (!additionalFile && (vType.second->getChildAdditionals().size() == 0)) {
device << (" <!-- VTypes -->\n");
return true;
}
}
}
}
return false;
}
bool
GNENet::writeRouteComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs, const bool additionalFile) const {
for (const auto& route : myAttributeCarriers->getDemandElements().at(SUMO_TAG_ROUTE)) {
if (ACs.count(route.second) > 0) {
if (additionalFile && (route.second->getChildAdditionals().size() != 0)) {
device << (" <!-- Routes (used in RouteProbReroutes and calibratorFlows) -->\n");
return true;
} else if (!additionalFile && (route.second->getChildAdditionals().size() == 0)) {
device << (" <!-- Routes -->\n");
return true;
}
}
}
return false;
}
bool
GNENet::writeRouteProbeComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
for (const auto& AC : ACs) {
if (AC->getTagProperty()->getTag() == SUMO_TAG_ROUTEPROBE) {
device << (" <!-- RouteProbes -->\n");
return true;
}
}
return false;
}
bool
GNENet::writeCalibratorComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
for (const auto& AC : ACs) {
if (AC->getTagProperty()->isCalibrator()) {
device << (" <!-- Calibrators -->\n");
return true;
}
}
return false;
}
bool
GNENet::writeStoppingPlaceComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
for (const auto& AC : ACs) {
if (AC->getTagProperty()->isStoppingPlace()) {
device << (" <!-- StoppingPlaces -->\n");
return true;
}
}
return false;
}
bool
GNENet::writeDetectorComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
for (const auto& AC : ACs) {
if (AC->getTagProperty()->isDetector()) {
device << (" <!-- Detectors -->\n");
return true;
}
}
return false;
}
bool
GNENet::writeOtherAdditionalsComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
for (const auto& AC : ACs) {
if (AC->getTagProperty()->isAdditionalPureElement() &&
!AC->getTagProperty()->isStoppingPlace() &&
!AC->getTagProperty()->isDetector() &&
!AC->getTagProperty()->isCalibrator() &&
(AC->getTagProperty()->getTag() != SUMO_TAG_ROUTEPROBE) &&
(AC->getTagProperty()->getTag() != SUMO_TAG_ACCESS) &&
(AC->getTagProperty()->getTag() != SUMO_TAG_PARKING_SPACE)) {
device << (" <!-- Other additionals -->\n");
return true;
}
}
return false;
}
bool
GNENet::writeShapesComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
for (const auto& AC : ACs) {
if (AC->getTagProperty()->isShapeElement() && !AC->getTagProperty()->isJuPedSimElement()) {
device << (" <!-- Shapes -->\n");
return true;
}
}
return false;
}
bool
GNENet::writeJuPedSimComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
for (const auto& AC : ACs) {
if (AC->getTagProperty()->isJuPedSimElement()) {
device << (" <!-- JuPedSim elements -->\n");
return true;
}
}
return false;
}
bool
GNENet::writeTAZComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
for (const auto& AC : ACs) {
if (AC->getTagProperty()->getTag() == SUMO_TAG_TAZ) {
device << (" <!-- TAZs -->\n");
return true;
}
}
return false;
}
bool
GNENet::writeWireComment(OutputDevice& device, const std::unordered_set<const GNEAttributeCarrier*>& ACs) const {
for (const auto& AC : ACs) {
if (AC->getTagProperty()->isWireElement()) {
device << (" <!-- Wires -->\n");
return true;
}
}
return false;
}
bool
GNENet::writeMeanDataEdgeComment(OutputDevice& device) const {
if (myAttributeCarriers->getMeanDatas().at(SUMO_TAG_MEANDATA_EDGE).size() > 0) {
device << (" <!-- MeanDataEdges -->\n");
return true;
}
return false;
}
bool
GNENet::writeMeanDataLaneComment(OutputDevice& device) const {
if (myAttributeCarriers->getMeanDatas().at(SUMO_TAG_MEANDATA_LANE).size() > 0) {
device << (" <!-- MeanDataLanes -->\n");
return true;
}
return false;
}
void
GNENet::saveTLSPrograms(const std::string& filename) {
OutputDevice& device = OutputDevice::getDevice(filename);
device.openTag("additionals");
NWWriter_SUMO::writeTrafficLights(device, getTLLogicCont());
device.close();
mySavingStatus->TLSSaved();
}
int
GNENet::getNumberOfTLSPrograms() const {
return -1;
}
void
GNENet::saveEdgeTypes(const std::string& filename) {
myNetBuilder->getTypeCont().clearTypes();
for (const auto& edgeType : myAttributeCarriers->getEdgeTypes()) {
myNetBuilder->getTypeCont().insertEdgeType(edgeType.first, edgeType.second);
for (int i = 0; i < (int)edgeType.second->getLaneTypes().size(); i++) {
myNetBuilder->getTypeCont().insertLaneType(edgeType.first, i,
edgeType.second->getLaneTypes().at(i)->speed,
edgeType.second->getLaneTypes().at(i)->permissions,
edgeType.second->getLaneTypes().at(i)->width,
edgeType.second->getLaneTypes().at(i)->attrs);
}
}
OutputDevice& device = OutputDevice::getDevice(filename);
device.openTag(SUMO_TAG_TYPES);
myNetBuilder->getTypeCont().writeEdgeTypes(device);
device.closeTag();
device.close();
}
void
GNENet::enableUpdateGeometry() {
myUpdateGeometryEnabled = true;
}
void
GNENet::disableUpdateGeometry() {
myUpdateGeometryEnabled = false;
}
bool
GNENet::isUpdateGeometryEnabled() const {
return myUpdateGeometryEnabled;
}
void
GNENet::enableUpdateData() {
myUpdateDataEnabled = true;
for (const auto& dataInterval : myAttributeCarriers->getDataIntervals()) {
dataInterval.second->updateGenericDataIDs();
dataInterval.second->updateAttributeColors();
}
}
void
GNENet::disableUpdateData() {
myUpdateDataEnabled = false;
}
bool
GNENet::isUpdateDataEnabled() const {
return myUpdateDataEnabled;
}
unsigned int&
GNENet::getJunctionIDCounter() {
return myJunctionIDCounter;
}
unsigned int&
GNENet::getEdgeIDCounter() {
return myEdgeIDCounter;
}
void
GNENet::initJunctionsAndEdges() {
for (const auto& edgeType : myNetBuilder->getTypeCont()) {
myAttributeCarriers->registerEdgeType(new GNEEdgeType(this, edgeType.first, edgeType.second));
}
for (const auto& nodeName : myNetBuilder->getNodeCont().getAllNames()) {
myAttributeCarriers->registerJunction(new GNEJunction(this, myNetBuilder->getNodeCont().retrieve(nodeName), true));
}
for (const auto& edgeName : myNetBuilder->getEdgeCont().getAllNames()) {
GNEEdge* edge = new GNEEdge(this, myNetBuilder->getEdgeCont().retrieve(edgeName), false, true);
myAttributeCarriers->registerEdge(edge);
edge->getFromJunction()->addChildElement(edge);
edge->getToJunction()->addChildElement(edge);
if (myGrid.getWidth() > 10e16 || myGrid.getHeight() > 10e16) {
throw ProcessError(TL("Network size exceeds 1 Lightyear. Please reconsider your inputs.") + std::string("\n"));
}
}
if (myAttributeCarriers->getEdges().size() == 0) {
myGrid.add(Boundary(-50, -50, 50, 50));
}
for (const auto& edge : myAttributeCarriers->getEdges()) {
for (const auto& lane : edge.second->getChildLanes()) {
lane->updateGeometry();
}
}
NBNodesEdgesSorter::sortNodesEdges(myNetBuilder->getNodeCont());
}
void
GNENet::initGNEConnections() {
for (const auto& edge : myAttributeCarriers->getEdges()) {
edge.second->remakeGNEConnections();
for (const auto& connection : edge.second->getGNEConnections()) {
connection->updateGeometry();
}
}
}
void
GNENet::computeAndUpdate(OptionsCont& neteditOptions, bool volatileOptions) {
std::set<std::string> liveExplicitTurnarounds;
for (const auto& explicitTurnarounds : myExplicitTurnarounds) {
if (myAttributeCarriers->getEdges().count(explicitTurnarounds) > 0) {
liveExplicitTurnarounds.insert(explicitTurnarounds);
}
}
for (const auto& junction : myAttributeCarriers->getJunctions()) {
removeGLObjectFromGrid(junction.second);
}
for (const auto& edge : myAttributeCarriers->getEdges()) {
removeGLObjectFromGrid(edge.second);
}
myNetBuilder->compute(neteditOptions, liveExplicitTurnarounds, volatileOptions);
if (neteditOptions.getBool("numerical-ids") || neteditOptions.isSet("reserved-ids")) {
myAttributeCarriers->remapJunctionAndEdgeIds();
}
if (!neteditOptions.getBool("offset.disable-normalization")) {
for (const auto& edge : myAttributeCarriers->getEdges()) {
edge.second->updateGeometry();
}
}
if (myViewNet != nullptr) {
myViewNet->getViewParent()->getInspectorFrame()->clearInspection();
}
myGrid.reset();
myGrid.add(GeoConvHelper::getFinal().getConvBoundary());
if (volatileOptions) {
if (myViewNet == nullptr) {
throw ProcessError("ViewNet doesn't exist");
}
myUpdateGeometryEnabled = false;
myViewNet->destroyPopup();
myViewNet->getUndoList()->clear();
myAttributeCarriers->clearJunctions();
myAttributeCarriers->clearEdges();
myAttributeCarriers->clearAdditionals();
myAttributeCarriers->clearDemandElements();
myUpdateGeometryEnabled = true;
initJunctionsAndEdges();
myAttributeCarriers->addDefaultVTypes();
} else {
for (const auto& junction : myAttributeCarriers->getJunctions()) {
junction.second->updateCenteringBoundary(false);
addGLObjectIntoGrid(junction.second);
}
for (const auto& edge : myAttributeCarriers->getEdges()) {
edge.second->updateCenteringBoundary(false);
addGLObjectIntoGrid(edge.second);
}
for (const auto& edge : myAttributeCarriers->getEdges()) {
edge.second->remakeGNEConnections(true);
}
for (const auto& junction : myAttributeCarriers->getJunctions()) {
junction.second->setLogicValid(true, nullptr);
junction.second->updateGeometryAfterNetbuild();
junction.second->rebuildGNEWalkingAreas();
}
for (const auto& edge : myAttributeCarriers->getEdges()) {
edge.second->updateGeometry();
}
}
myNeedRecompute = false;
}
void
GNENet::replaceInListAttribute(GNEAttributeCarrier* ac, SumoXMLAttr key, const std::string& which, const std::string& by, GNEUndoList* undoList) {
assert(ac->getTagProperty()->getAttributeProperties(key)->isList());
std::vector<std::string> values = GNEAttributeCarrier::parse<std::vector<std::string> >(ac->getAttribute(key));
std::vector<std::string> newValues;
bool lastBy = false;
for (auto v : values) {
if (v == which && !lastBy) {
newValues.push_back(by);
} else {
newValues.push_back(v);
}
lastBy = v == by;
}
ac->setAttribute(key, toString(newValues), undoList);
}