LCOV - code coverage report
Current view: top level - src/netimport/vissim/tempstructs - NIVissimConnectionCluster.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 162 312 51.9 %
Date: 2024-05-01 15:34:42 Functions: 16 33 48.5 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      14             : /// @file    NIVissimConnectionCluster.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Michael Behrisch
      18             : /// @date    Sept 2002
      19             : ///
      20             : // -------------------
      21             : /****************************************************************************/
      22             : #include <config.h>
      23             : 
      24             : #include <algorithm>
      25             : #include <iostream>
      26             : #include <cassert>
      27             : #include <iterator>
      28             : #include <utils/geom/Boundary.h>
      29             : #include <utils/geom/GeomHelper.h>
      30             : #include <utils/common/VectorHelper.h>
      31             : #include <utils/common/MsgHandler.h>
      32             : #include <utils/common/ToString.h>
      33             : #include "NIVissimConnection.h"
      34             : #include "NIVissimDisturbance.h"
      35             : #include "NIVissimNodeCluster.h"
      36             : #include "NIVissimNodeDef.h"
      37             : #include "NIVissimEdge.h"
      38             : #include "NIVissimTL.h"
      39             : #include "NIVissimConnectionCluster.h"
      40             : 
      41             : 
      42             : // ===========================================================================
      43             : // static members
      44             : // ===========================================================================
      45             : NIVissimConnectionCluster::ContType NIVissimConnectionCluster::myClusters;
      46             : int NIVissimConnectionCluster::myFirstFreeID = 100000;
      47             : int NIVissimConnectionCluster::myStaticBlaID = 0;
      48             : 
      49             : 
      50             : 
      51             : // ===========================================================================
      52             : // method definitions
      53             : // ===========================================================================
      54             : // ---------------------------------------------------------------------------
      55             : // NIVissimConnectionCluster::NodeSubCluster - methods
      56             : // ---------------------------------------------------------------------------
      57           0 : NIVissimConnectionCluster::NodeSubCluster::NodeSubCluster(NIVissimConnection* c) {
      58           0 :     add(c);
      59           0 : }
      60             : 
      61             : 
      62           0 : NIVissimConnectionCluster::NodeSubCluster::~NodeSubCluster() {}
      63             : 
      64             : 
      65             : void
      66           0 : NIVissimConnectionCluster::NodeSubCluster::add(NIVissimConnection* c) {
      67           0 :     myBoundary.add(c->getBoundingBox());
      68           0 :     myConnections.push_back(c);
      69           0 : }
      70             : 
      71             : 
      72             : void
      73           0 : NIVissimConnectionCluster::NodeSubCluster::add(const NIVissimConnectionCluster::NodeSubCluster& c) {
      74           0 :     for (ConnectionCont::const_iterator i = c.myConnections.begin(); i != c.myConnections.end(); i++) {
      75           0 :         add(*i);
      76             :     }
      77           0 : }
      78             : 
      79             : 
      80             : int
      81           0 : NIVissimConnectionCluster::NodeSubCluster::size() const {
      82           0 :     return (int)myConnections.size();
      83             : }
      84             : 
      85             : 
      86             : std::vector<int>
      87           0 : NIVissimConnectionCluster::NodeSubCluster::getConnectionIDs() const {
      88             :     std::vector<int> ret;
      89           0 :     int id = NIVissimConnectionCluster::getNextFreeNodeID();
      90           0 :     for (ConnectionCont::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
      91           0 :         ret.push_back((*i)->getID());
      92           0 :         (*i)->setNodeCluster(id);
      93             :     }
      94           0 :     return ret;
      95             : }
      96             : 
      97             : 
      98             : bool
      99           0 : NIVissimConnectionCluster::NodeSubCluster::overlapsWith(
     100             :     const NIVissimConnectionCluster::NodeSubCluster& c,
     101             :     double offset) {
     102             :     assert(myBoundary.xmax() >= myBoundary.xmin());
     103             :     assert(c.myBoundary.xmax() >= c.myBoundary.xmin());
     104           0 :     return myBoundary.overlapsWith(c.myBoundary, offset);
     105             : }
     106             : 
     107             : 
     108             : 
     109             : // ---------------------------------------------------------------------------
     110             : // NIVissimConnectionCluster - methods
     111             : // ---------------------------------------------------------------------------
     112        1139 : NIVissimConnectionCluster::NIVissimConnectionCluster(
     113        1139 :     const std::vector<int>& connections, int nodeCluster, int edgeid)
     114        1139 :     : myConnections(connections), myNodeCluster(nodeCluster),
     115        1139 :       myBlaID(myStaticBlaID++) {
     116        1139 :     recomputeBoundary();
     117        1139 :     myClusters.push_back(this);
     118             :     assert(edgeid > 0);
     119        1139 :     if (edgeid >= 0) {
     120        1139 :         myEdges.push_back(edgeid);
     121             :     }
     122             :     // add information about incoming and outgoing edges
     123        2993 :     for (std::vector<int>::const_iterator i = connections.begin(); i != connections.end(); i++) {
     124        1854 :         NIVissimConnection* c = NIVissimConnection::dictionary(*i);
     125             :         assert(c != 0);
     126        1854 :         myOutgoingEdges.push_back(c->getToEdgeID());
     127        1854 :         myIncomingEdges.push_back(c->getFromEdgeID());
     128             :         assert(c->getFromEdgeID() == edgeid || c->getToEdgeID() == edgeid);
     129             :     }
     130        1139 :     VectorHelper<int>::removeDouble(myIncomingEdges);
     131        1139 :     VectorHelper<int>::removeDouble(myOutgoingEdges);
     132        1139 : }
     133             : 
     134             : 
     135           0 : NIVissimConnectionCluster::NIVissimConnectionCluster(
     136             :     const std::vector<int>& connections, const Boundary& boundary,
     137           0 :     int nodeCluster, const std::vector<int>& edges)
     138           0 :     : myConnections(connections), myBoundary(boundary),
     139           0 :       myNodeCluster(nodeCluster), myEdges(edges) {
     140           0 :     myClusters.push_back(this);
     141           0 :     recomputeBoundary();
     142             :     assert(myBoundary.xmax() >= myBoundary.xmin());
     143             :     // add information about incoming and outgoing edges
     144           0 :     for (std::vector<int>::const_iterator i = connections.begin(); i != connections.end(); i++) {
     145           0 :         NIVissimConnection* c = NIVissimConnection::dictionary(*i);
     146             :         assert(c != 0);
     147           0 :         myOutgoingEdges.push_back(c->getToEdgeID());
     148           0 :         myIncomingEdges.push_back(c->getFromEdgeID());
     149             :         assert(find(edges.begin(), edges.end(), c->getFromEdgeID()) != edges.end()
     150             :                ||
     151             :                std::find(edges.begin(), edges.end(), c->getToEdgeID()) != edges.end());
     152             :     }
     153           0 :     VectorHelper<int>::removeDouble(myIncomingEdges);
     154           0 :     VectorHelper<int>::removeDouble(myOutgoingEdges);
     155           0 : }
     156             : 
     157             : 
     158        2278 : NIVissimConnectionCluster::~NIVissimConnectionCluster() {}
     159             : 
     160             : 
     161             : 
     162             : int
     163           0 : NIVissimConnectionCluster::getNextFreeNodeID() {
     164           0 :     return myFirstFreeID++;
     165             : }
     166             : 
     167             : 
     168             : bool
     169       74033 : NIVissimConnectionCluster::overlapsWith(NIVissimConnectionCluster* c,
     170             :                                         double offset) const {
     171             :     assert(myBoundary.xmax() >= myBoundary.xmin());
     172             :     assert(c->myBoundary.xmax() >= c->myBoundary.xmin());
     173       74033 :     return c->myBoundary.overlapsWith(myBoundary, offset);
     174             : }
     175             : 
     176             : 
     177             : void
     178         791 : NIVissimConnectionCluster::add(NIVissimConnectionCluster* c) {
     179             :     assert(myBoundary.xmax() >= myBoundary.xmin());
     180             :     assert(c->myBoundary.xmax() >= c->myBoundary.xmin());
     181         791 :     myBoundary.add(c->myBoundary);
     182        2127 :     for (std::vector<int>::iterator i = c->myConnections.begin(); i != c->myConnections.end(); i++) {
     183        1336 :         myConnections.push_back(*i);
     184             :     }
     185         791 :     VectorHelper<int>::removeDouble(myConnections);
     186             :     assert(myNodeCluster == -1 || c->myNodeCluster == -1);
     187         791 :     if (myNodeCluster == -1) {
     188         791 :         myNodeCluster = c->myNodeCluster;
     189             :     }
     190             :     // inform edges about merging
     191             :     //  !!! merge should be done within one method
     192        1594 :     for (std::vector<int>::iterator j = c->myEdges.begin(); j != c->myEdges.end(); j++) {
     193         803 :         NIVissimEdge::dictionary(*j)->mergedInto(c, this);
     194             :     }
     195         791 :     copy(c->myEdges.begin(), c->myEdges.end(), back_inserter(myEdges));
     196             :     copy(c->myIncomingEdges.begin(), c->myIncomingEdges.end(),
     197         791 :          back_inserter(myIncomingEdges));
     198             :     copy(c->myOutgoingEdges.begin(), c->myOutgoingEdges.end(),
     199         791 :          back_inserter(myOutgoingEdges));
     200         791 :     VectorHelper<int>::removeDouble(myEdges);
     201         791 :     VectorHelper<int>::removeDouble(myIncomingEdges);
     202         791 :     VectorHelper<int>::removeDouble(myOutgoingEdges);
     203         791 : }
     204             : 
     205             : 
     206             : 
     207             : void
     208           9 : NIVissimConnectionCluster::joinBySameEdges(double offset) {
     209             :     // !!! ...
     210             :     // Further, we try to omit joining of overlaping nodes. This is done by holding
     211             :     //  the lists of incoming and outgoing edges and incrementally building the nodes
     212             :     //  regarding this information
     213             :     std::vector<NIVissimConnectionCluster*> joinAble;
     214             :     int pos = 0;
     215             :     ContType::iterator i = myClusters.begin();
     216             :     // step1 - faster but no complete
     217         737 :     while (i != myClusters.end()) {
     218             :         joinAble.clear();
     219             :         ContType::iterator j = i + 1;
     220             : 
     221             :         // check whether every combination has been processed
     222       65070 :         while (j != myClusters.end()) {
     223             :             // check whether the current clusters overlap
     224       64342 :             if ((*i)->joinable(*j, offset)) {
     225         785 :                 joinAble.push_back(*j);
     226             :             }
     227             :             j++;
     228             :         }
     229         728 :         for (std::vector<NIVissimConnectionCluster*>::iterator k = joinAble.begin();
     230        1513 :                 k != joinAble.end(); k++) {
     231             :             // add the overlaping cluster
     232         785 :             (*i)->add(*k);
     233             :             // erase the overlaping cluster
     234         785 :             delete *k;
     235         785 :             myClusters.erase(find(myClusters.begin(), myClusters.end(), *k));
     236             :         }
     237             :         //
     238         728 :         if (joinAble.size() > 0) {
     239             :             i = myClusters.begin() + pos;
     240             :             // clear temporary storages
     241             :             joinAble.clear();
     242             :         } else {
     243             :             i++;
     244         354 :             pos++;
     245             :         }
     246             :     }
     247             :     //
     248             :     pos = 0;
     249             :     i = myClusters.begin();
     250         363 :     while (i != myClusters.end()) {
     251             :         ContType::iterator j = i + 1;
     252             :         // check whether every combination has been processed
     253       10581 :         while (j != myClusters.end()) {
     254             :             // check whether the current clusters overlap
     255       10227 :             if ((*i)->joinable(*j, offset)) {
     256           0 :                 joinAble.push_back(*j);
     257             :             }
     258             :             j++;
     259             :         }
     260         354 :         for (std::vector<NIVissimConnectionCluster*>::iterator k = joinAble.begin();
     261         354 :                 k != joinAble.end(); k++) {
     262             :             // add the overlaping cluster
     263           0 :             (*i)->add(*k);
     264             :             // erase the overlaping cluster
     265           0 :             delete *k;
     266           0 :             myClusters.erase(find(myClusters.begin(), myClusters.end(), *k));
     267             :         }
     268             :         //
     269         354 :         if (joinAble.size() > 0) {
     270             :             i = myClusters.begin();
     271             :             // clear temporary storages
     272             :             joinAble.clear();
     273             :             pos = 0;
     274             :         } else {
     275             :             i++;
     276             :             pos++;
     277             :         }
     278             :     }
     279             :     // check for weak district connections
     280             :     //  (junctions made up by district connections, where prohibitions are not
     281             :     //   modelled properly)
     282             :     pos = 0;
     283             :     i = myClusters.begin();
     284         582 :     while (i != myClusters.end()) {
     285             :         ContType::iterator j = i + 1;
     286             :         // check whether every combination has been processed
     287       20817 :         while (j != myClusters.end()) {
     288             :             // check whether the current clusters overlap
     289       20244 :             if ((*i)->isWeakDistrictConnRealisation(*j)) {
     290           6 :                 joinAble.push_back(*j);
     291             :             }
     292             :             j++;
     293             :         }
     294         573 :         for (std::vector<NIVissimConnectionCluster*>::iterator k = joinAble.begin();
     295         579 :                 k != joinAble.end(); k++) {
     296             :             // add the overlaping cluster
     297           6 :             (*i)->add(*k);
     298             :             // erase the overlaping cluster
     299           6 :             delete *k;
     300           6 :             myClusters.erase(find(myClusters.begin(), myClusters.end(), *k));
     301             :         }
     302             :         //
     303         573 :         if (joinAble.size() > 0) {
     304             :             i = myClusters.begin();
     305             :             // clear temporary storages
     306             :             joinAble.clear();
     307             :             pos = 0;
     308             :         } else {
     309             :             i++;
     310             :             pos++;
     311             :         }
     312             :     }
     313           9 : }
     314             : 
     315             : 
     316             : bool
     317       74569 : NIVissimConnectionCluster::joinable(NIVissimConnectionCluster* c2, double offset) {
     318             :     // join clusters which have at least one connection in common
     319       74569 :     if (VectorHelper<int>::subSetExists(myConnections, c2->myConnections)) {
     320             :         return true;
     321             :     }
     322             : 
     323             :     // connections shall overlap otherwise
     324       74033 :     if (!overlapsWith(c2, offset)) {
     325             :         return false;
     326             :     }
     327             : 
     328             :     // at least one of the clusters shall not be assigned to a node in previous (!!!??)
     329        1113 :     if (hasNodeCluster() && c2->hasNodeCluster()) {
     330             :         return false;
     331             :     }
     332             : 
     333             :     // join clusters which where connections do disturb each other
     334        2226 :     if (VectorHelper<int>::subSetExists(c2->getDisturbanceParticipators(), myConnections)
     335        1113 :             ||
     336        2211 :             VectorHelper<int>::subSetExists(getDisturbanceParticipators(), c2->myConnections)) {
     337             : 
     338             :         return true;
     339             :     }
     340             : 
     341             : 
     342             :     // join clusters which do share the same incoming or outgoing edges (not mutually)
     343             :     std::vector<int> extendedOutgoing1;
     344             :     std::vector<int> extendedIncoming1;
     345             :     std::vector<int> extendedOutgoing2;
     346             :     std::vector<int> extendedIncoming2;
     347        1098 :     if (myIncomingEdges.size() > 1 || c2->myIncomingEdges.size() > 1) {
     348             :         extendedOutgoing1 =
     349         542 :             extendByToTreatAsSame(myOutgoingEdges, myIncomingEdges);
     350             :         extendedIncoming1 =
     351         542 :             extendByToTreatAsSame(myIncomingEdges, myOutgoingEdges);
     352             :         extendedOutgoing2 =
     353         542 :             extendByToTreatAsSame(c2->myOutgoingEdges, c2->myIncomingEdges);
     354             :         extendedIncoming2 =
     355        1084 :             extendByToTreatAsSame(c2->myIncomingEdges, c2->myOutgoingEdges);
     356             :     } else {
     357         556 :         extendedOutgoing1 = myIncomingEdges;
     358         556 :         extendedIncoming1 = myOutgoingEdges;
     359         556 :         extendedOutgoing2 = c2->myIncomingEdges;
     360         556 :         extendedIncoming2 = c2->myOutgoingEdges;
     361             :     }
     362             : 
     363        1098 :     if (VectorHelper<int>::subSetExists(extendedOutgoing1, extendedOutgoing2)
     364        1098 :             ||
     365        1032 :             VectorHelper<int>::subSetExists(extendedIncoming1, extendedIncoming2)
     366             :        ) {
     367         234 :         return true;
     368             :     }
     369             :     return false;
     370             : }
     371             : 
     372             : 
     373             : bool
     374       20244 : NIVissimConnectionCluster::isWeakDistrictConnRealisation(NIVissimConnectionCluster* c2) {
     375       20740 :     if ((myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1)) {
     376             :         return false;
     377             :     }
     378        7877 :     if ((c2->myIncomingEdges.size() == 1 && c2->myOutgoingEdges.size() == 1)) {
     379             :         return false;
     380             :     }
     381             : 
     382             :     // ok, may be the other way round
     383        4253 :     if (myIncomingEdges.size() == 1 && c2->myOutgoingEdges.size() == 1) {
     384             :         return c2->isWeakDistrictConnRealisation(this);
     385             :     }
     386             :     // connections must cross
     387             :     bool crosses = false;
     388       21368 :     for (std::vector<int>::const_iterator j1 = myConnections.begin(); j1 != myConnections.end() && !crosses; j1++) {
     389       17611 :         const PositionVector& g1 = NIVissimConnection::dictionary(*j1)->getGeometry();
     390       81521 :         for (const int j2 : c2->myConnections) {
     391       63940 :             const PositionVector& g2 = NIVissimConnection::dictionary(j2)->getGeometry();
     392       63940 :             if (g1.intersects(g2)) {
     393             :                 crosses = true;
     394             :                 break;
     395             :             }
     396             :         }
     397             :     }
     398        3757 :     if (!crosses) {
     399             :         return false;
     400             :     }
     401             :     // ok, check for connection
     402          30 :     if (myOutgoingEdges.size() != 1 || c2->myIncomingEdges.size() != 1) {
     403             :         return false;
     404             :     }
     405             :     // check whether the connection is bidirectional
     406          15 :     NIVissimEdge* oe = NIVissimEdge::dictionary(myOutgoingEdges[0]);
     407          15 :     NIVissimEdge* ie = NIVissimEdge::dictionary(c2->myIncomingEdges[0]);
     408          15 :     if (oe == nullptr || ie == nullptr) {
     409             :         return false;
     410             :     }
     411          15 :     return fabs(GeomHelper::angleDiff(oe->getGeometry().beginEndAngle(), ie->getGeometry().beginEndAngle())) < DEG2RAD(5);
     412             : }
     413             : 
     414             : 
     415             : bool
     416           0 : NIVissimConnectionCluster::liesOnSameEdgesEnd(NIVissimConnectionCluster* cc2) {
     417             :     //
     418           0 :     for (std::vector<int>::iterator i = myConnections.begin(); i != myConnections.end(); i++) {
     419           0 :         NIVissimConnection* c1 = NIVissimConnection::dictionary(*i);
     420           0 :         for (std::vector<int>::iterator j = cc2->myConnections.begin(); j != cc2->myConnections.end(); j++) {
     421           0 :             NIVissimConnection* c2 = NIVissimConnection::dictionary(*j);
     422           0 :             if (c1->getFromEdgeID() == c2->getFromEdgeID()) {
     423           0 :                 NIVissimEdge* e = NIVissimEdge::dictionary(c1->getFromEdgeID());
     424           0 :                 const PositionVector& g = e->getGeometry();
     425           0 :                 double pos1 = GeomHelper::nearest_offset_on_line_to_point2D(
     426           0 :                                   g.front(), g.back(), c1->getBoundary().getCenter());
     427           0 :                 double pos2 = GeomHelper::nearest_offset_on_line_to_point2D(
     428           0 :                                   g.front(), g.back(), c2->getBoundary().getCenter());
     429           0 :                 if (pos1 <= 5.0 && pos2 <= 5.0) {
     430             :                     return true;
     431             :                 }
     432             :             }
     433           0 :             if (c1->getToEdgeID() == c2->getToEdgeID()) {
     434           0 :                 NIVissimEdge* e = NIVissimEdge::dictionary(c1->getFromEdgeID());
     435           0 :                 const PositionVector& g = e->getGeometry();
     436           0 :                 double pos1 = GeomHelper::nearest_offset_on_line_to_point2D(
     437           0 :                                   g.front(), g.back(), c1->getBoundary().getCenter());
     438           0 :                 double pos2 = GeomHelper::nearest_offset_on_line_to_point2D(
     439           0 :                                   g.front(), g.back(), c2->getBoundary().getCenter());
     440           0 :                 if (pos1 >= g.length() - 5.0 && pos2 >= g.length() - 5.0) {
     441             :                     return true;
     442             :                 }
     443             :             }
     444             :         }
     445             :     }
     446             :     return false;
     447             : }
     448             : 
     449             : 
     450             : std::vector<int>
     451        2168 : NIVissimConnectionCluster::extendByToTreatAsSame(const std::vector<int>& iv1,
     452             :         const std::vector<int>& iv2) const {
     453        2168 :     std::vector<int> ret(iv1);
     454        6179 :     for (std::vector<int>::const_iterator i = iv1.begin(); i != iv1.end(); i++) {
     455        4011 :         NIVissimEdge* e = NIVissimEdge::dictionary(*i);
     456        4011 :         const std::vector<NIVissimEdge*> treatAsSame = e->getToTreatAsSame();
     457        4275 :         for (std::vector<NIVissimEdge*>::const_iterator j = treatAsSame.begin(); j != treatAsSame.end(); j++) {
     458         264 :             if (find(iv2.begin(), iv2.end(), (*j)->getID()) == iv2.end()) {
     459         264 :                 ret.push_back((*j)->getID());
     460             :             }
     461             :         }
     462             :     }
     463        2168 :     return ret;
     464             : }
     465             : 
     466             : std::vector<int>
     467        2211 : NIVissimConnectionCluster::getDisturbanceParticipators() {
     468             :     std::vector<int> ret;
     469        7188 :     for (std::vector<int>::iterator i = myConnections.begin(); i != myConnections.end(); i++) {
     470        4977 :         NIVissimConnection* c = NIVissimConnection::dictionary(*i);
     471        4977 :         const std::vector<int>& disturbances = c->getDisturbances();
     472        8995 :         for (std::vector<int>::const_iterator j = disturbances.begin(); j != disturbances.end(); j++) {
     473        4018 :             NIVissimDisturbance* d = NIVissimDisturbance::dictionary(*j);
     474        4018 :             ret.push_back(d->getEdgeID());
     475        4018 :             ret.push_back(d->getDisturbanceID());
     476             :         }
     477             :     }
     478        2211 :     return ret;
     479             : }
     480             : 
     481             : 
     482             : void
     483           9 : NIVissimConnectionCluster::buildNodeClusters() {
     484         357 :     for (ContType::iterator i = myClusters.begin(); i != myClusters.end(); i++) {
     485             :         std::vector<int> disturbances;
     486             :         std::vector<int> tls;
     487             :         std::vector<int> nodes;
     488             :         int tlsid = -1;
     489             :         int nodeid = -1;
     490         348 :         if ((*i)->myConnections.size() > 0) {
     491         348 :             (*i)->recomputeBoundary();
     492         696 :             disturbances = NIVissimDisturbance::getWithin((*i)->myBoundary);
     493             :         }
     494         348 :         nodes = (*i)->myNodes;//NIVissimTL::getWithin((*i)->myBoundary, 5.0);
     495         348 :         if (nodes.size() > 1) {
     496           0 :             WRITE_WARNING(TL("NIVissimConnectionCluster:More than a single node"));
     497             :             //          throw 1; // !!! eigentlich sollte hier nur eine Ampelanlage sein
     498             :         }
     499         348 :         if (nodes.size() > 0) {
     500           0 :             nodeid = nodes[0];
     501             :         }
     502             :         //
     503             :         //
     504         348 :         int id = NIVissimNodeCluster::dictionary(
     505         348 :                      nodeid, tlsid, (*i)->myConnections,
     506         348 :                      disturbances, (*i)->myIncomingEdges.size() < 2);
     507             :         assert((*i)->myNodeCluster == id || (*i)->myNodeCluster < 0);
     508         348 :         (*i)->myNodeCluster = id;
     509             :     }
     510           9 : }
     511             : 
     512             : 
     513             : void
     514           0 : NIVissimConnectionCluster::_debugOut(std::ostream& into) {
     515           0 :     for (ContType::iterator i = myClusters.begin(); i != myClusters.end(); i++) {
     516           0 :         std::vector<int> connections = (*i)->myConnections;
     517           0 :         for (std::vector<int>::iterator j = connections.begin(); j != connections.end(); j++) {
     518           0 :             if (j != connections.begin()) {
     519           0 :                 into << ", ";
     520             :             }
     521           0 :             into << *j;
     522             :         }
     523           0 :         into << "(" << (*i)->myBoundary << ")" << std::endl;
     524             :     }
     525             :     into << "---------------------------" << std::endl;
     526           0 : }
     527             : 
     528             : 
     529             : 
     530             : bool
     531        1113 : NIVissimConnectionCluster::hasNodeCluster() const {
     532        1113 :     return myNodeCluster != -1;
     533             : }
     534             : 
     535             : 
     536             : void
     537           0 : NIVissimConnectionCluster::removeConnections(const NodeSubCluster& c) {
     538           0 :     for (NodeSubCluster::ConnectionCont::const_iterator i = c.myConnections.begin(); i != c.myConnections.end(); i++) {
     539           0 :         NIVissimConnection* conn = *i;
     540           0 :         int connid = conn->getID();
     541           0 :         std::vector<int>::iterator j = std::find(myConnections.begin(), myConnections.end(), connid);
     542           0 :         if (j != myConnections.end()) {
     543           0 :             myConnections.erase(j);
     544             :         }
     545             :     }
     546           0 :     recomputeBoundary();
     547           0 : }
     548             : 
     549             : 
     550             : void
     551        1487 : NIVissimConnectionCluster::recomputeBoundary() {
     552        1487 :     myBoundary = Boundary();
     553        4268 :     for (std::vector<int>::iterator i = myConnections.begin(); i != myConnections.end(); i++) {
     554        2781 :         NIVissimConnection* c = NIVissimConnection::dictionary(*i);
     555        2781 :         if (c != nullptr) {
     556        2781 :             myBoundary.add(c->getFromGeomPosition());
     557        2781 :             myBoundary.add(c->getToGeomPosition());
     558        2781 :             if (c->getGeometry().size() != 0) {
     559        2148 :                 myBoundary.add(c->getGeometry().getBoxBoundary());
     560             :             }
     561             :         }
     562             :     }
     563             :     assert(myBoundary.xmax() >= myBoundary.xmin());
     564        1487 : }
     565             : 
     566             : 
     567             : NBNode*
     568        1061 : NIVissimConnectionCluster::getNBNode() const {
     569        1061 :     return NIVissimNodeCluster::dictionary(myNodeCluster)->getNBNode();
     570             : }
     571             : 
     572             : 
     573             : bool
     574        1397 : NIVissimConnectionCluster::around(const Position& p, double offset) const {
     575             :     assert(myBoundary.xmax() >= myBoundary.xmin());
     576        1397 :     return myBoundary.around(p, offset);
     577             : }
     578             : 
     579             : 
     580             : 
     581             : void
     582           0 : NIVissimConnectionCluster::recheckEdges() {
     583             :     assert(myConnections.size() != 0);
     584             :     // remove the cluster from all edges at first
     585             :     std::vector<int>::iterator i;
     586           0 :     for (i = myEdges.begin(); i != myEdges.end(); i++) {
     587           0 :         NIVissimEdge* edge = NIVissimEdge::dictionary(*i);
     588           0 :         edge->removeFromConnectionCluster(this);
     589             :     }
     590             :     // clear edge information
     591           0 :     myEdges.clear();
     592             :     // recheck which edges do still participate and add edges
     593           0 :     for (i = myConnections.begin(); i != myConnections.end(); i++) {
     594           0 :         NIVissimConnection* c = NIVissimConnection::dictionary(*i);
     595             :         assert(myBoundary.xmax() >= myBoundary.xmin());
     596           0 :         if (myBoundary.around(c->getFromGeomPosition(), 5)) {
     597           0 :             myEdges.push_back(c->getFromEdgeID());
     598             :         }
     599             :         assert(myBoundary.xmax() >= myBoundary.xmin());
     600           0 :         if (myBoundary.around(c->getToGeomPosition(), 5)) {
     601           0 :             myEdges.push_back(c->getToEdgeID());
     602             :         }
     603             :     }
     604             :     // connect edges
     605           0 :     for (i = myEdges.begin(); i != myEdges.end(); i++) {
     606           0 :         NIVissimEdge* edge = NIVissimEdge::dictionary(*i);
     607           0 :         edge->addToConnectionCluster(this);
     608             :     }
     609           0 : }
     610             : 
     611             : 
     612             : double
     613        4282 : NIVissimConnectionCluster::getPositionForEdge(int edgeid) const {
     614             :     // return the middle of the connections when there are any
     615        4282 :     if (myConnections.size() != 0) {
     616             :         double sum = 0;
     617             :         int part = 0;
     618             :         std::vector<int>::const_iterator i;
     619       20384 :         for (i = myConnections.begin(); i != myConnections.end(); i++) {
     620       16102 :             NIVissimConnection* c = NIVissimConnection::dictionary(*i);
     621       16102 :             if (c->getFromEdgeID() == edgeid) {
     622        3672 :                 part++;
     623        3672 :                 sum += c->getFromPosition();
     624             :             }
     625       16102 :             if (c->getToEdgeID() == edgeid) {
     626        3554 :                 part++;
     627        3554 :                 sum += c->getToPosition();
     628             :             }
     629             :         }
     630        4282 :         if (part > 0) {
     631        4282 :             return sum / (double) part;
     632             :         }
     633             :     }
     634             :     // use the position of the node if possible
     635           0 :     if (myNodeCluster >= 0) {
     636             :         // try to find the nearest point on the edge
     637             :         //  !!! only the main geometry is regarded
     638             :         NIVissimNodeDef* node =
     639           0 :             NIVissimNodeDef::dictionary(myNodeCluster);
     640           0 :         if (node != nullptr) {
     641           0 :             double pos = node->getEdgePosition(edgeid);
     642           0 :             if (pos >= 0) {
     643             :                 return pos;
     644             :             }
     645             :         }
     646             :         /*
     647             :                 double try1 = GeomHelper::nearest_offset_on_line_to_point(
     648             :                     edge->getBegin2D(), edge->getEnd2D(), node->getPos());
     649             :                 if(try1>=0) {
     650             :                     return try1;
     651             :                 }
     652             :                 // try to use simple distance
     653             :                 double dist1 =
     654             :                     GeomHelper::distance(node->getPos(), edge->getBegin2D());
     655             :                 double dist2 =
     656             :                     GeomHelper::distance(node->getPos(), edge->getEnd2D());
     657             :                 return dist1<dist2
     658             :                     ? 0 : edge->getLength();
     659             :                     */
     660             :     }
     661             :     // what else?
     662           0 :     WRITE_WARNING(TL("NIVissimConnectionCluster: how to get an edge's position?"));
     663             :     // !!!
     664             :     assert(myBoundary.xmin() <= myBoundary.xmax());
     665           0 :     NIVissimEdge* edge = NIVissimEdge::dictionary(edgeid);
     666           0 :     std::vector<int>::const_iterator i = std::find(myEdges.begin(), myEdges.end(), edgeid);
     667           0 :     if (i == myEdges.end()) {
     668             :         // edge does not exist!?
     669           0 :         throw 1;
     670             :     }
     671           0 :     const PositionVector& edgeGeom = edge->getGeometry();
     672           0 :     Position p = GeomHelper::crossPoint(myBoundary, edgeGeom);
     673           0 :     return GeomHelper::nearest_offset_on_line_to_point2D(
     674             :                edgeGeom.front(), edgeGeom.back(), p);
     675             : }
     676             : 
     677             : 
     678             : 
     679             : void
     680           9 : NIVissimConnectionCluster::clearDict() {
     681         357 :     for (ContType::iterator i = myClusters.begin(); i != myClusters.end(); i++) {
     682         348 :         delete (*i);
     683             :     }
     684             :     myClusters.clear();
     685           9 :     myFirstFreeID = 100000;
     686           9 : }
     687             : 
     688             : 
     689             : PositionVector
     690           0 : NIVissimConnectionCluster::getIncomingContinuationGeometry(NIVissimEdge* e) const {
     691             :     // collect connection where this edge is the incoming one
     692             :     std::vector<NIVissimConnection*> edgeIsIncoming;
     693           0 :     for (std::vector<int>::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
     694           0 :         NIVissimConnection* c = NIVissimConnection::dictionary(*i);
     695           0 :         if (c->getFromEdgeID() == e->getID()) {
     696           0 :             edgeIsIncoming.push_back(c);
     697             :         }
     698             :     }
     699             :     //
     700           0 :     if (edgeIsIncoming.size() == 0) {
     701           0 :         return PositionVector();
     702             :     }
     703             :     // sort connected edges in same direction
     704           0 :     sort(edgeIsIncoming.begin(), edgeIsIncoming.end(),
     705           0 :          same_direction_sorter(e->getGeometry().beginEndAngle()));
     706           0 :     NIVissimConnection* c = *(edgeIsIncoming.begin());
     707           0 :     return c->getGeometry();
     708             : }
     709             : 
     710             : 
     711             : 
     712             : NIVissimConnection*
     713           0 : NIVissimConnectionCluster::getIncomingContinuation(NIVissimEdge* e) const {
     714             :     // collect connection where this edge is the incoming one
     715             :     std::vector<NIVissimConnection*> edgeIsIncoming;
     716           0 :     for (std::vector<int>::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
     717           0 :         NIVissimConnection* c = NIVissimConnection::dictionary(*i);
     718           0 :         if (c->getFromEdgeID() == e->getID()) {
     719           0 :             edgeIsIncoming.push_back(c);
     720             :         }
     721             :     }
     722             :     //
     723           0 :     if (edgeIsIncoming.size() == 0) {
     724             :         return nullptr;
     725             :     }
     726             :     // sort connected edges in same direction
     727           0 :     sort(edgeIsIncoming.begin(), edgeIsIncoming.end(),
     728           0 :          same_direction_sorter(e->getGeometry().beginEndAngle()));
     729           0 :     return *(edgeIsIncoming.begin());
     730             : }
     731             : 
     732             : 
     733             : 
     734             : PositionVector
     735           0 : NIVissimConnectionCluster::getOutgoingContinuationGeometry(NIVissimEdge* e) const {
     736             :     // collect connection where this edge is the outgoing one
     737             :     std::vector<NIVissimConnection*> edgeIsOutgoing;
     738           0 :     for (std::vector<int>::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
     739           0 :         NIVissimConnection* c = NIVissimConnection::dictionary(*i);
     740           0 :         if (c->getToEdgeID() == e->getID()) {
     741           0 :             edgeIsOutgoing.push_back(c);
     742             :         }
     743             :     }
     744             :     //
     745           0 :     if (edgeIsOutgoing.size() == 0) {
     746           0 :         return PositionVector();
     747             :     }
     748             :     // sort connected edges in same direction
     749           0 :     sort(edgeIsOutgoing.begin(), edgeIsOutgoing.end(),
     750           0 :          same_direction_sorter(e->getGeometry().beginEndAngle()));
     751           0 :     NIVissimConnection* c = *(edgeIsOutgoing.begin());
     752           0 :     return c->getGeometry();
     753             : }
     754             : 
     755             : 
     756             : NIVissimConnection*
     757           0 : NIVissimConnectionCluster::getOutgoingContinuation(NIVissimEdge* e) const {
     758             :     // collect connection where this edge is the outgoing one
     759             :     std::vector<NIVissimConnection*> edgeIsOutgoing;
     760           0 :     for (std::vector<int>::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
     761           0 :         NIVissimConnection* c = NIVissimConnection::dictionary(*i);
     762           0 :         if (c->getToEdgeID() == e->getID()) {
     763           0 :             edgeIsOutgoing.push_back(c);
     764             :         }
     765             :     }
     766             :     //
     767           0 :     if (edgeIsOutgoing.size() == 0) {
     768             :         return nullptr;
     769             :     }
     770             :     // sort connected edges in same direction
     771           0 :     sort(edgeIsOutgoing.begin(), edgeIsOutgoing.end(),
     772           0 :          same_direction_sorter(e->getGeometry().beginEndAngle()));
     773           0 :     return *(edgeIsOutgoing.begin());
     774             : }
     775             : 
     776             : 
     777             : /****************************************************************************/

Generated by: LCOV version 1.14