Path: blob/main/src/netimport/vissim/tempstructs/NIVissimEdge.cpp
169684 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file NIVissimEdge.cpp14/// @author Daniel Krajzewicz15/// @author Jakob Erdmann16/// @author Michael Behrisch17/// @date Sept 200218///19// A temporary storage for edges imported from Vissim20/****************************************************************************/21#include <config.h>2223#include <string>24#include <algorithm>25#include <map>26#include <cassert>27#include <iomanip>28#include <cmath>29#include <iostream>30#include <sstream>31#include <iterator>32#include <utils/common/ToString.h>33#include <utils/geom/PositionVector.h>34#include <utils/geom/GeomHelper.h>35#include <utils/distribution/DistributionCont.h>36#include <netbuild/NBNode.h>37#include <netbuild/NBNodeCont.h>38#include <utils/options/OptionsCont.h>39#include "NIVissimNodeCluster.h"40#include "NIVissimDistrictConnection.h"41#include "NIVissimClosedLanesVector.h"42#include "NIVissimConnection.h"43#include "NIVissimDisturbance.h"44#include "NIVissimEdge.h"45#include <utils/common/MsgHandler.h>464748// ===========================================================================49// static members50// ===========================================================================51NIVissimEdge::DictType NIVissimEdge::myDict;52int NIVissimEdge::myMaxID = 0;53std::vector<std::string> NIVissimEdge::myLanesWithMissingSpeeds;545556// ===========================================================================57// method definitions58// ===========================================================================59NIVissimEdge::connection_position_sorter::connection_position_sorter(int edgeid)60: myEdgeID(edgeid) {}616263int64NIVissimEdge::connection_position_sorter::operator()(int c1id,65int c2id) const {66NIVissimConnection* c1 = NIVissimConnection::dictionary(c1id);67NIVissimConnection* c2 = NIVissimConnection::dictionary(c2id);68double pos1 =69c1->getFromEdgeID() == myEdgeID70? c1->getFromPosition() : c1->getToPosition();71double pos2 =72c2->getFromEdgeID() == myEdgeID73? c2->getFromPosition() : c2->getToPosition();74return pos1 < pos2;75}767778798081828384NIVissimEdge::connection_cluster_position_sorter::connection_cluster_position_sorter(int edgeid)85: myEdgeID(edgeid) {}868788int89NIVissimEdge::connection_cluster_position_sorter::operator()(90NIVissimConnectionCluster* cc1,91NIVissimConnectionCluster* cc2) const {92double pos1 = cc1->getPositionForEdge(myEdgeID);93double pos2 = cc2->getPositionForEdge(myEdgeID);94if (pos2 < 0 || pos1 < 0) {95cc1->getPositionForEdge(myEdgeID);96cc2->getPositionForEdge(myEdgeID);97}98assert(pos1 >= 0 && pos2 >= 0);99return pos1 < pos2;100}101102103104105NIVissimEdge::NIVissimEdge(int id, const std::string& name,106const std::string& type,107std::vector<double> laneWidths,108double zuschlag1, double zuschlag2,109double /*length*/, const PositionVector& geom,110const NIVissimClosedLanesVector& clv) :111NIVissimAbstractEdge(id, geom),112myName(name), myType(type), myNoLanes((int)laneWidths.size()),113myLaneWidths(laneWidths),114myZuschlag1(zuschlag1), myZuschlag2(zuschlag2),115myClosedLanes(clv),116myLaneSpeeds(myNoLanes, -1),117myAmWithinJunction(false)118//, mySpeed(-1)119{120assert(myNoLanes >= 0);121if (myMaxID < myID) {122myMaxID = myID;123}124}125126127NIVissimEdge::~NIVissimEdge() {128for (NIVissimClosedLanesVector::iterator i = myClosedLanes.begin(); i != myClosedLanes.end(); i++) {129delete (*i);130}131myClosedLanes.clear();132}133134135bool136NIVissimEdge::dictionary(int id, const std::string& name,137const std::string& type, int noLanes,138double zuschlag1, double zuschlag2, double length,139const PositionVector& geom,140const NIVissimClosedLanesVector& clv) {141NIVissimEdge* o = new NIVissimEdge(id, name, type, std::vector<double>(noLanes, NBEdge::UNSPECIFIED_WIDTH),142zuschlag1, zuschlag2, length, geom, clv);143if (!dictionary(id, o)) {144delete o;145return false;146}147return true;148}149150151152bool153NIVissimEdge::dictionary(int id, NIVissimEdge* o) {154DictType::iterator i = myDict.find(id);155if (i == myDict.end()) {156myDict[id] = o;157return true;158}159return false;160}161162163164NIVissimEdge*165NIVissimEdge::dictionary(int id) {166DictType::iterator i = myDict.find(id);167if (i == myDict.end()) {168return nullptr;169}170return (*i).second;171}172173174void175NIVissimEdge::buildConnectionClusters() {176const double MAX_CLUSTER_DISTANCE = 10;177// build clusters for all edges made up from not previously assigne178// connections179for (DictType::iterator i = myDict.begin(); i != myDict.end(); i++) {180int edgeid = (*i).first;181NIVissimEdge* edge = (*i).second;182// get all connectors using this edge183std::vector<int> connectors = edge->myIncomingConnections;184copy(edge->myOutgoingConnections.begin(), edge->myOutgoingConnections.end(), back_inserter(connectors));185if (connectors.size() == 0) {186continue;187}188// sort the connectors by the place on the edge189sort(connectors.begin(), connectors.end(), connection_position_sorter(edgeid));190// try to cluster the connections participating within the current edge191std::vector<int> currentCluster;192std::vector<int>::iterator j = connectors.begin();193bool outgoing = NIVissimConnection::dictionary(*j)->getFromEdgeID() == (*i).first;194double position = outgoing195? NIVissimConnection::dictionary(*j)->getFromPosition()196: NIVissimConnection::dictionary(*j)->getToPosition();197198// skip connections already in a cluster199// !!! (?)200while (j != connectors.end() && NIVissimConnection::dictionary(*j)->hasNodeCluster()) {201++j;202}203if (j == connectors.end()) {204continue;205}206currentCluster.push_back(*j);207do {208if (j + 1 != connectors.end() && !NIVissimConnection::dictionary(*j)->hasNodeCluster()) {209bool n_outgoing = NIVissimConnection::dictionary(*(j + 1))->getFromEdgeID() == edgeid;210double n_position = n_outgoing211? NIVissimConnection::dictionary(*(j + 1))->getFromPosition()212: NIVissimConnection::dictionary(*(j + 1))->getToPosition();213if (n_outgoing == outgoing && fabs(n_position - position) < MAX_CLUSTER_DISTANCE) {214// ok, in same cluster as prior215currentCluster.push_back(*(j + 1));216} else {217// start new cluster218VectorHelper<int>::removeDouble(currentCluster);219edge->myConnectionClusters.push_back(new NIVissimConnectionCluster(currentCluster, -1, edgeid));220currentCluster.clear();221currentCluster.push_back(*(j + 1));222}223outgoing = n_outgoing;224position = n_position;225}226j++;227} while (j != connectors.end());228// add last connection229if (currentCluster.size() > 0) {230VectorHelper<int>::removeDouble(currentCluster);231edge->myConnectionClusters.push_back(new NIVissimConnectionCluster(currentCluster, -1, edgeid));232}233}234}235236237void238NIVissimEdge::dict_buildNBEdges(NBDistrictCont& dc, NBNodeCont& nc,239NBEdgeCont& ec, double offset) {240for (DictType::iterator i = myDict.begin(); i != myDict.end(); i++) {241NIVissimEdge* edge = (*i).second;242edge->buildNBEdge(dc, nc, ec, offset);243}244}245246247void248NIVissimEdge::dict_propagateSpeeds() {249DictType::iterator i;250for (i = myDict.begin(); i != myDict.end(); i++) {251NIVissimEdge* edge = (*i).second;252edge->setDistrictSpeed();253}254for (i = myDict.begin(); i != myDict.end(); i++) {255NIVissimEdge* edge = (*i).second;256edge->propagateSpeed(-1, std::vector<int>());257}258for (int j = 0; j < 3; j++) {259for (i = myDict.begin(); i != myDict.end(); i++) {260NIVissimEdge* edge = (*i).second;261edge->propagateOwn();262}263for (i = myDict.begin(); i != myDict.end(); i++) {264NIVissimEdge* edge = (*i).second;265edge->checkUnconnectedLaneSpeeds();266}267}268}269270271void272NIVissimEdge::checkUnconnectedLaneSpeeds() {273for (int i = 0; i < (int) myLaneSpeeds.size(); i++) {274if (myLaneSpeeds[i] == -1) {275double speed = -1;276int j1 = i - 1; // !!! recheck - j1 may become negative?277int j2 = i;278while (j2 != (int) myLaneSpeeds.size() && myLaneSpeeds[j2] == -1) {279j2++;280}281if (j1 < 0) {282if (j2 < (int) myLaneSpeeds.size()) {283speed = myLaneSpeeds[j2];284}285} else {286if (j2 >= (int) myLaneSpeeds.size()) {287speed = myLaneSpeeds[j1];288} else {289speed = (myLaneSpeeds[j1] + myLaneSpeeds[j2]) / (double) 2.0;290}291}292if (speed == -1) {293continue;294}295myLaneSpeeds[i] = speed;296std::vector<NIVissimConnection*> connected = getOutgoingConnected(i);297for (std::vector<NIVissimConnection*>::iterator j = connected.begin(); j != connected.end(); j++) {298NIVissimConnection* c = *j;299NIVissimEdge* e = NIVissimEdge::dictionary(c->getToEdgeID());300// propagate301e->propagateSpeed(/*dc, */speed, c->getToLanes());302}303}304}305}306307308void309NIVissimEdge::propagateOwn() {310for (int i = 0; i < (int) myLaneSpeeds.size(); i++) {311if (myLaneSpeeds[i] == -1) {312continue;313}314std::vector<NIVissimConnection*> connected = getOutgoingConnected(i);315for (std::vector<NIVissimConnection*>::iterator j = connected.begin(); j != connected.end(); j++) {316NIVissimConnection* c = *j;317NIVissimEdge* e = NIVissimEdge::dictionary(c->getToEdgeID());318// propagate319e->propagateSpeed(/*dc, */myLaneSpeeds[i], c->getToLanes());320}321}322}323324325void326NIVissimEdge::propagateSpeed(double speed, std::vector<int> forLanes) {327// if no lane is given, all set be set328if (forLanes.size() == 0) {329for (int i = 0; i < myNoLanes; i++) {330forLanes.push_back((int) i);331}332}333// for the case of a first call334// go through the lanes335for (std::vector<int>::const_iterator i = forLanes.begin(); i < forLanes.end(); i++) {336// check whether a speed was set before337if (myLaneSpeeds[*i] != -1) {338// do not reset it from incoming339continue;340}341// check whether the lane has a new speed to set342if ((int) myPatchedSpeeds.size() > *i && myPatchedSpeeds[*i] != -1) {343// use it344speed = getRealSpeed(/*dc, */myPatchedSpeeds[*i]);345}346// check whether a speed is given347if (speed == -1) {348// do nothing if not349continue;350}351// set the lane's speed to the given352myLaneSpeeds[*i] = speed;353// propagate the speed further354// get the list of connected edges355std::vector<NIVissimConnection*> connected = getOutgoingConnected(*i);356// go through the list357for (std::vector<NIVissimConnection*>::iterator j = connected.begin(); j != connected.end(); j++) {358NIVissimConnection* c = *j;359NIVissimEdge* e = NIVissimEdge::dictionary(c->getToEdgeID());360// propagate361e->propagateSpeed(/*dc, */speed, c->getToLanes());362}363}364}365366367368void369NIVissimEdge::setDistrictSpeed() {370if (myDistrictConnections.size() > 0) {371double pos = *(myDistrictConnections.begin());372if (pos < getLength() - pos) {373NIVissimDistrictConnection* d =374NIVissimDistrictConnection::dict_findForEdge(myID);375if (d != nullptr) {376double speed = d->getMeanSpeed(/*dc*/);377if (speed == -1) {378return;379}380for (int i = 0; i < myNoLanes; i++) {381myLaneSpeeds[i] = speed;382// propagate the speed further383// get the list of connected edges384std::vector<NIVissimConnection*> connected = getOutgoingConnected(i);385// go through the list386for (std::vector<NIVissimConnection*>::iterator j = connected.begin(); j != connected.end(); j++) {387NIVissimConnection* c = *j;388NIVissimEdge* e = NIVissimEdge::dictionary(c->getToEdgeID());389// propagate390e->propagateSpeed(/*dc, */speed, c->getToLanes());391}392}393}394}395}396}397398399std::vector<NIVissimConnection*>400NIVissimEdge::getOutgoingConnected(int lane) const {401std::vector<NIVissimConnection*> ret;402for (std::vector<int>::const_iterator i = myOutgoingConnections.begin(); i != myOutgoingConnections.end(); i++) {403NIVissimConnection* c = NIVissimConnection::dictionary(*i);404const std::vector<int>& lanes = c->getFromLanes();405if (find(lanes.begin(), lanes.end(), lane) != lanes.end()) {406NIVissimEdge* e = NIVissimEdge::dictionary(c->getToEdgeID());407if (e != nullptr) {408ret.push_back(c);409}410}411}412return ret;413}414415416void417NIVissimEdge::buildNBEdge(NBDistrictCont& dc, NBNodeCont& nc, NBEdgeCont& ec,418double sameNodesOffset) {419// build the edge420std::pair<NIVissimConnectionCluster*, NBNode*> fromInf, toInf;421NBNode* fromNode, *toNode;422fromNode = toNode = nullptr;423sort(myConnectionClusters.begin(), myConnectionClusters.end(), connection_cluster_position_sorter(myID));424sort(myDistrictConnections.begin(), myDistrictConnections.end());425ConnectionClusters tmpClusters = myConnectionClusters;426if (tmpClusters.size() != 0) {427sort(tmpClusters.begin(), tmpClusters.end(), connection_cluster_position_sorter(myID));428// get or build the from-node429// A node may have to be build when the edge starts or ends at430// a parking place or something like this431fromInf = getFromNode(nc, tmpClusters);432fromNode = fromInf.second;433// get or build the to-node434//if(tmpClusters.size()>0) {435toInf = getToNode(nc, tmpClusters);436toNode = toInf.second;437if (fromInf.first != 0 && toNode != nullptr && fromInf.first->around(toNode->getPosition())) {438WRITE_WARNINGF(TL("Will not build edge '%'."), toString(myID));439myAmWithinJunction = true;440return;441}442//}443// if both nodes are the same, resolve the problem otherwise444if (fromNode == toNode) {445std::pair<NBNode*, NBNode*> tmp = resolveSameNode(nc, sameNodesOffset, fromNode, toNode);446if (fromNode != tmp.first) {447fromInf.first = 0;448}449if (toNode != tmp.second) {450toInf.first = 0;451}452fromNode = tmp.first;453toNode = tmp.second;454}455}456457//458if (fromNode == nullptr) {459fromInf.first = 0;460Position pos = myGeom[0];461fromNode = new NBNode(toString<int>(myID) + "-SourceNode", pos, SumoXMLNodeType::NOJUNCTION);462if (!nc.insert(fromNode)) {463throw ProcessError(TLF("Could not insert node '%' to nodes container.", fromNode->getID()));464}465}466if (toNode == nullptr) {467toInf.first = 0;468Position pos = myGeom[-1];469toNode = new NBNode(toString<int>(myID) + "-DestinationNode", pos, SumoXMLNodeType::NOJUNCTION);470if (!nc.insert(toNode)) {471throw ProcessError(TLF("Could not insert node '%' to nodes container.", toNode->getID()));472}473}474475// build the edge476double avgSpeed = 0;477for (int i = 0; i < myNoLanes; i++) {478if ((int)myLaneSpeeds.size() <= i || myLaneSpeeds[i] == -1) {479myLanesWithMissingSpeeds.push_back(toString(myID) + "_" + toString(i));480avgSpeed += OptionsCont::getOptions().getFloat("vissim.default-speed");481} else {482avgSpeed += myLaneSpeeds[i];483}484}485avgSpeed /= (double) myLaneSpeeds.size();486avgSpeed *= OptionsCont::getOptions().getFloat("vissim.speed-norm");487488if (fromNode == toNode) {489WRITE_WARNINGF(TL("Could not build edge '%'; would connect same node."), toString(myID));490return;491}492493NBEdge* buildEdge = new NBEdge(toString<int>(myID), fromNode, toNode, myType,494avgSpeed / 3.6, NBEdge::UNSPECIFIED_FRICTION, myNoLanes, -1,495NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET,496myGeom, LaneSpreadFunction::CENTER, myName, "", true);497for (int i = 0; i < myNoLanes; i++) {498buildEdge->setLaneWidth(i, myLaneWidths[i]);499if ((int) myLaneSpeeds.size() <= i || myLaneSpeeds[i] == -1) {500buildEdge->setSpeed(i, OptionsCont::getOptions().getFloat("vissim.default-speed") / (double) 3.6);501} else {502buildEdge->setSpeed(i, myLaneSpeeds[i] / (double) 3.6);503}504}505ec.insert(buildEdge);506// check whether the edge contains any other clusters507if (tmpClusters.size() > 0) {508bool cont = true;509for (ConnectionClusters::iterator j = tmpClusters.begin(); cont && j != tmpClusters.end(); ++j) {510// split the edge at the previously build node511std::string nextID = buildEdge->getID() + "[1]";512cont = ec.splitAt(dc, buildEdge, (*j)->getNBNode());513// !!! what to do if the edge could not be split?514buildEdge = ec.retrieve(nextID);515}516}517}518519520double521NIVissimEdge::getRealSpeed(int distNo) {522std::string id = toString<int>(distNo);523Distribution* dist = DistributionCont::dictionary("speed", id);524if (dist == nullptr) {525WRITE_WARNINGF(TL("The referenced speed distribution '%' is not known."), id);526return -1;527}528assert(dist != 0);529double speed = dist->getMax();530if (speed < 0 || speed > 1000) {531WRITE_WARNINGF(TL("What about distribution '%'"), toString<int>(distNo));532}533return speed;534}535536/*537bool538NIVissimEdge::recheckSpeedPatches()539{540// int speed_idx = -1;541// check set speeds542if(myPatchedSpeeds.size()!=0) {543std::vector<double>::iterator i =544std::find(myPatchedSpeeds.begin(), myPatchedSpeeds.end(), -1);545if(myPatchedSpeeds.size()!=myNoLanes||i!=myPatchedSpeeds.end()) {546cot << "Warning! Not all lanes are patched! (edge:" << myID << ")." << endl;547}548//549if(std::vector<double>Helper::maxValue(myPatchedSpeeds)!=std::vector<double>Helper::minValue(myPatchedSpeeds)) {550cot << "Warning! Not all lanes have the same speed!! (edge:" << myID << ")." << endl;551}552//553/ // !!! ist natuerlich Quatsch - erst recht, wenn Edges zusammengefasst werden554speed = std::vector<double>Helper::sum(myPatchedSpeeds);555speed /= (double) myPatchedSpeeds.size();*/556/* return true;557}558if(myDistrictConnections.size()>0) {559double pos = *(myDistrictConnections.begin());560// if(pos<10) {561NIVissimDistrictConnection *d =562NIVissimDistrictConnection::dict_findForEdge(myID);563if(d!=0) {564return true;565// speed = d->getMeanSpeed();566}567// }568// return true;569}570return false;571}572*/573574std::pair<NIVissimConnectionCluster*, NBNode*>575NIVissimEdge::getFromNode(NBNodeCont& nc, ConnectionClusters& clusters) {576// changed MAX_DISTANCE from 10 to 3.5, because 3.5 is the default lane width in VISSIM577const double MAX_DISTANCE = 3.5;578assert(clusters.size() >= 1);579const Position& beg = myGeom.front();580NIVissimConnectionCluster* c = *(clusters.begin());581// check whether the edge starts within a already build node582if (c->around(beg, MAX_DISTANCE)) {583clusters.erase(clusters.begin());584return std::pair<NIVissimConnectionCluster*, NBNode*>585(c, c->getNBNode());586}587// check for a parking place at the begin588if (myDistrictConnections.size() > 0) {589double pos = *(myDistrictConnections.begin());590if (pos < 10) {591NBNode* node = new NBNode(toString<int>(myID) + "-begin", beg, SumoXMLNodeType::NOJUNCTION);592if (!nc.insert(node)) {593throw 1;594}595while (myDistrictConnections.size() > 0 && *(myDistrictConnections.begin()) < 10) {596myDistrictConnections.erase(myDistrictConnections.begin());597}598return std::pair<NIVissimConnectionCluster*, NBNode*>(static_cast<NIVissimConnectionCluster*>(nullptr), node);599}600}601// build a new node for the edge's begin otherwise602NBNode* node = new NBNode(toString<int>(myID) + "-begin", beg, SumoXMLNodeType::NOJUNCTION);603if (!nc.insert(node)) {604throw 1;605}606return std::pair<NIVissimConnectionCluster*, NBNode*>(static_cast<NIVissimConnectionCluster*>(nullptr), node);607}608609610std::pair<NIVissimConnectionCluster*, NBNode*>611NIVissimEdge::getToNode(NBNodeCont& nc, ConnectionClusters& clusters) {612const Position& end = myGeom.back();613if (clusters.size() > 0) {614const double MAX_DISTANCE = 10.;615assert(clusters.size() >= 1);616NIVissimConnectionCluster* c = *(clusters.end() - 1);617// check whether the edge ends within a already build node618if (c->around(end, MAX_DISTANCE)) {619clusters.erase(clusters.end() - 1);620return std::pair<NIVissimConnectionCluster*, NBNode*>(c, c->getNBNode());621}622}623// check for a parking place at the end624if (myDistrictConnections.size() > 0) {625double pos = *(myDistrictConnections.end() - 1);626if (pos > myGeom.length() - 10) {627NBNode* node = new NBNode(toString<int>(myID) + "-end", end, SumoXMLNodeType::NOJUNCTION);628if (!nc.insert(node)) {629throw 1;630}631while (myDistrictConnections.size() > 0 && *(myDistrictConnections.end() - 1) < myGeom.length() - 10) {632myDistrictConnections.erase(myDistrictConnections.end() - 1);633}634return std::pair<NIVissimConnectionCluster*, NBNode*>(static_cast<NIVissimConnectionCluster*>(nullptr), node);635}636}637638// build a new node for the edge's end otherwise639NBNode* node = new NBNode(toString<int>(myID) + "-end", end, SumoXMLNodeType::NOJUNCTION);640if (!nc.insert(node)) {641throw 1;642}643return std::pair<NIVissimConnectionCluster*, NBNode*>(static_cast<NIVissimConnectionCluster*>(nullptr), node);644/*645if (clusters.size()>0) {646NIVissimConnectionCluster *c = *(clusters.end()-1);647clusters.erase(clusters.end()-1);648return std::pair<NIVissimConnectionCluster*, NBNode*>(c, c->getNBNode());649} else {650// !!! self-loop edge?!651return std::pair<NIVissimConnectionCluster*, NBNode*>(static_cast<NIVissimConnectionCluster*>(0), (*(myConnectionClusters.begin()))->getNBNode());652}653*/654}655656657std::pair<NBNode*, NBNode*>658NIVissimEdge::remapOneOfNodes(NBNodeCont& nc,659NIVissimDistrictConnection* d,660NBNode* fromNode, NBNode* toNode) {661std::string nid = "ParkingPlace" + toString<int>(d->getID());662if (d->geomPosition().distanceTo(fromNode->getPosition())663<664d->geomPosition().distanceTo(toNode->getPosition())) {665666NBNode* newNode = new NBNode(nid,667fromNode->getPosition(),668SumoXMLNodeType::NOJUNCTION);669nc.erase(fromNode);670nc.insert(newNode);671return std::pair<NBNode*, NBNode*>(newNode, toNode);672} else {673NBNode* newNode = new NBNode(nid,674toNode->getPosition(),675SumoXMLNodeType::NOJUNCTION);676nc.erase(toNode);677nc.insert(newNode);678return std::pair<NBNode*, NBNode*>(fromNode, newNode);679}680}681682683684std::pair<NBNode*, NBNode*>685NIVissimEdge::resolveSameNode(NBNodeCont& nc, double offset,686NBNode* prevFrom, NBNode* prevTo) {687// check whether the edge is connected to a district688// use it if so689NIVissimDistrictConnection* d =690NIVissimDistrictConnection::dict_findForEdge(myID);691if (d != nullptr) {692Position pos = d->geomPosition();693double position = d->getPosition();694// the district is at the begin of the edge695if (myGeom.length() - position > position) {696std::string nid = "ParkingPlace" + toString<int>(d->getID());697NBNode* node = nc.retrieve(nid);698if (node == nullptr) {699node = new NBNode(nid,700pos, SumoXMLNodeType::NOJUNCTION);701if (!nc.insert(node)) {702throw 1;703}704}705return std::pair<NBNode*, NBNode*>(node, prevTo);706}707// the district is at the end of the edge708else {709std::string nid = "ParkingPlace" + toString<int>(d->getID());710NBNode* node = nc.retrieve(nid);711if (node == nullptr) {712node = new NBNode(nid, pos, SumoXMLNodeType::NOJUNCTION);713if (!nc.insert(node)) {714throw 1;715}716}717assert(node != 0);718return std::pair<NBNode*, NBNode*>(prevFrom, node);719}720}721// otherwise, check whether the edge is some kind of722// a dead end...723// check which end is nearer to the node centre724if (myConnectionClusters.size() == 1) {725NBNode* node = prevFrom; // it is the same as getToNode()726727NIVissimConnectionCluster* c = *(myConnectionClusters.begin());728// no end node given729if (c->around(myGeom.front(), offset) && !c->around(myGeom.back(), offset)) {730NBNode* end = new NBNode(731toString<int>(myID) + "-End",732myGeom.back(),733SumoXMLNodeType::NOJUNCTION);734if (!nc.insert(end)) {735throw 1;736}737return std::pair<NBNode*, NBNode*>(node, end);738}739740// no begin node given741if (!c->around(myGeom.front(), offset) && c->around(myGeom.back(), offset)) {742NBNode* beg = new NBNode(743toString<int>(myID) + "-Begin",744myGeom.front(),745SumoXMLNodeType::NOJUNCTION);746if (!nc.insert(beg)) {747std::cout << "nope, NIVissimDisturbance" << std::endl;748throw 1;749}750return std::pair<NBNode*, NBNode*>(beg, node);751}752753// self-loop edge - both points lie within the same cluster754if (c->around(myGeom.front()) && c->around(myGeom.back())) {755return std::pair<NBNode*, NBNode*>(node, node);756}757}758// what to do in other cases?759// It simply is a self-looping edge....760return std::pair<NBNode*, NBNode*>(prevFrom, prevTo);761}762763764765766void767NIVissimEdge::setNodeCluster(int nodeid) {768myNode = nodeid;769}770771772void773NIVissimEdge::buildGeom() {}774775776void777NIVissimEdge::addIncomingConnection(int id) {778myIncomingConnections.push_back(id);779}780781782void783NIVissimEdge::addOutgoingConnection(int id) {784myOutgoingConnections.push_back(id);785}786787788789void790NIVissimEdge::mergedInto(NIVissimConnectionCluster* old,791NIVissimConnectionCluster* act) {792ConnectionClusters::iterator i =793std::find(myConnectionClusters.begin(), myConnectionClusters.end(), old);794if (i != myConnectionClusters.end()) {795myConnectionClusters.erase(i);796}797i = std::find(myConnectionClusters.begin(), myConnectionClusters.end(), act);798if (i == myConnectionClusters.end()) {799myConnectionClusters.push_back(act);800}801}802803804805void806NIVissimEdge::removeFromConnectionCluster(NIVissimConnectionCluster* c) {807ConnectionClusters::iterator i =808std::find(myConnectionClusters.begin(), myConnectionClusters.end(), c);809assert(i != myConnectionClusters.end());810myConnectionClusters.erase(i);811}812813814void815NIVissimEdge::addToConnectionCluster(NIVissimConnectionCluster* c) {816ConnectionClusters::iterator i =817std::find(myConnectionClusters.begin(), myConnectionClusters.end(), c);818if (i == myConnectionClusters.end()) {819myConnectionClusters.push_back(c);820}821}822823824Position // !!! reference?825NIVissimEdge::getBegin2D() const {826return myGeom[0];827}828829830Position // !!! reference?831NIVissimEdge::getEnd2D() const {832return myGeom[-1];833}834835836double837NIVissimEdge::getLength() const {838return myGeom.length();839}840841842void843NIVissimEdge::checkDistrictConnectionExistanceAt(double pos) {844if (find(myDistrictConnections.begin(), myDistrictConnections.end(), pos) == myDistrictConnections.end()) {845myDistrictConnections.push_back(pos);846/* int id = NIVissimConnection::getMaxID() + 1;847std::vector<int> currentCluster;848currentCluster.push_back(id);849myConnectionClusters.push_back(850new NIVissimConnectionCluster(currentCluster, -1, myID));*/851}852}853854855void856NIVissimEdge::setSpeed(int lane, int speedDist) {857while ((int)myPatchedSpeeds.size() <= lane) {858myPatchedSpeeds.push_back(-1);859}860myPatchedSpeeds[lane] = speedDist;861}862863864void865NIVissimEdge::dict_checkEdges2Join() {866// go through the edges867for (DictType::iterator i1 = myDict.begin(); i1 != myDict.end(); i1++) {868// retrieve needed values from the first edge869NIVissimEdge* e1 = (*i1).second;870const PositionVector& g1 = e1->getGeometry();871// check all other edges872DictType::iterator i2 = i1;873i2++;874for (; i2 != myDict.end(); i2++) {875// retrieve needed values from the second edge876NIVissimEdge* e2 = (*i2).second;877const PositionVector& g2 = e2->getGeometry();878// get the connection description879NIVissimConnection* c = e1->getConnectionTo(e2);880if (c == nullptr) {881c = e2->getConnectionTo(e1);882}883// the edge must not be a direct contiuation of the other884if (c != nullptr) {885if ((c->getFromEdgeID() == e1->getID() && fabs(c->getFromPosition() - e1->getGeometry().length()) < 5)886||887(c->getFromEdgeID() == e2->getID() && fabs(c->getFromPosition() - e2->getGeometry().length()) < 5)) {888889continue;890}891}892// only parallel edges which do end at the same node893// should be joined894// check for parallelity895// !!! the usage of an explicit value is not very fine896if (fabs(GeomHelper::angleDiff(g1.beginEndAngle(), g2.beginEndAngle())) > DEG2RAD(2.0)) {897// continue if the lines are not parallel898continue;899}900901// check whether the same node is approached902// (the distance between the ends should not be too large)903// !!! the usage of an explicit value is not very fine904if (g1.back().distanceTo(g2.back()) > 10) {905// continue if the lines do not end at the same length906continue;907}908// ok, seem to be different lanes for the same edge909// mark as possibly joined later910e1->addToTreatAsSame(e2);911e2->addToTreatAsSame(e1);912}913}914}915916917bool918NIVissimEdge::addToTreatAsSame(NIVissimEdge* e) {919if (e == this) {920return false;921}922// check whether this edge already knows about the other923if (find(myToTreatAsSame.begin(), myToTreatAsSame.end(), e) == myToTreatAsSame.end()) {924myToTreatAsSame.push_back(e);925return true;926} else {927return false; // !!! check this928}929/*930//931std::vector<NIVissimEdge*>::iterator i;932// add to all other that shall be treated as same933bool changed = true;934while (changed) {935changed = false;936for (i = myToTreatAsSame.begin(); !changed && i != myToTreatAsSame.end(); i++) {937changed |= (*i)->addToTreatAsSame(e);938}939for (i = myToTreatAsSame.begin(); !changed && i != myToTreatAsSame.end(); i++) {940changed |= e->addToTreatAsSame(*i);941}942}943*/944}945946NIVissimConnection*947NIVissimEdge::getConnectionTo(NIVissimEdge* e) {948std::vector<int>::iterator i;949for (i = myIncomingConnections.begin(); i != myIncomingConnections.end(); i++) {950NIVissimConnection* c = NIVissimConnection::dictionary(*i);951if (c->getFromEdgeID() == e->getID()) {952return c;953}954}955for (i = myOutgoingConnections.begin(); i != myOutgoingConnections.end(); i++) {956NIVissimConnection* c = NIVissimConnection::dictionary(*i);957if (c->getToEdgeID() == e->getID()) {958return c;959}960}961return nullptr;962}963964965const std::vector<NIVissimEdge*>&966NIVissimEdge::getToTreatAsSame() const {967return myToTreatAsSame;968}969970971void972NIVissimEdge::reportUnsetSpeeds() {973if (myLanesWithMissingSpeeds.size() == 0) {974return;975}976std::ostringstream str;977str << "The following lanes have no explicit speed information:\n ";978for (std::vector<std::string>::iterator i = myLanesWithMissingSpeeds.begin(); i != myLanesWithMissingSpeeds.end(); ++i) {979if (i != myLanesWithMissingSpeeds.begin()) {980str << ", ";981}982str << *i;983}984WRITE_WARNING(str.str());985}986987988NIVissimEdge*989NIVissimEdge::getBestIncoming() const {990// @todo seems as this would have been a hard hack!991/*992for (std::vector<int>::const_iterator i = myIncomingConnections.begin(); i != myIncomingConnections.end(); ++i) {993NIVissimConnection* c = NIVissimConnection::dictionary(*i);994return NIVissimEdge::dictionary(c->getFromEdgeID());995}996return 0;997*/998if (myIncomingConnections.size() != 0) {999return NIVissimEdge::dictionary(NIVissimConnection::dictionary(myIncomingConnections.front())->getFromEdgeID());1000}1001return nullptr;1002}100310041005NIVissimEdge*1006NIVissimEdge::getBestOutgoing() const {1007// @todo seems as this would have been a hard hack!1008/*1009for (std::vector<int>::const_iterator i = myOutgoingConnections.begin(); i != myOutgoingConnections.end(); ++i) {1010NIVissimConnection* c = NIVissimConnection::dictionary(*i);1011return NIVissimEdge::dictionary(c->getToEdgeID());1012}1013return 0;1014*/1015if (myOutgoingConnections.size() != 0) {1016return NIVissimEdge::dictionary(NIVissimConnection::dictionary(myOutgoingConnections.front())->getToEdgeID());1017}1018return nullptr;1019}102010211022/****************************************************************************/102310241025