LCOV - code coverage report
Current view: top level - src/netgen - NGNet.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.1 % 154 151
Test Date: 2025-11-13 15:38:19 Functions: 80.0 % 15 12

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2003-2025 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    NGNet.cpp
      15              : /// @author  Markus Hartinger
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Michael Behrisch
      18              : /// @author  Jakob Erdmann
      19              : /// @date    Mar, 2003
      20              : ///
      21              : // The class storing the generated network
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <iostream>
      26              : #include <stdlib.h>
      27              : #include <stdio.h>
      28              : #include <string.h>
      29              : #include <cmath>
      30              : #include <netbuild/NBNode.h>
      31              : #include <netbuild/NBNodeCont.h>
      32              : #include <netbuild/NBEdge.h>
      33              : #include <netbuild/NBEdgeCont.h>
      34              : #include <netbuild/NBNetBuilder.h>
      35              : #include <utils/common/ToString.h>
      36              : #include <utils/common/RandHelper.h>
      37              : #include <utils/common/StringUtils.h>
      38              : #include <utils/options/OptionsCont.h>
      39              : #include <utils/distribution/Distribution_Parameterized.h>
      40              : #include "NGNet.h"
      41              : 
      42              : 
      43              : // ===========================================================================
      44              : // method definitions
      45              : // ===========================================================================
      46           88 : NGNet::NGNet(NBNetBuilder& nb) :
      47           88 :     myLastID(0),
      48           88 :     myAlphaIDs(OptionsCont::getOptions().getBool("alphanumerical-ids")),
      49           88 :     myNetBuilder(nb) {
      50           88 : }
      51              : 
      52              : 
      53           88 : NGNet::~NGNet() {
      54         8353 :     for (NGEdgeList::iterator ni = myEdgeList.begin(); ni != myEdgeList.end(); ++ni) {
      55         8265 :         delete *ni;
      56              :     }
      57         5435 :     for (NGNodeList::iterator ni = myNodeList.begin(); ni != myNodeList.end(); ++ni) {
      58         5347 :         delete *ni;
      59              :     }
      60           88 : }
      61              : 
      62              : 
      63              : std::string
      64        73355 : NGNet::getNextFreeID() {
      65        73355 :     return toString<int>(++myLastID);
      66              : }
      67              : 
      68              : 
      69              : NGNode*
      70            0 : NGNet::findNode(int xID, int yID) {
      71       156879 :     for (NGNodeList::iterator ni = myNodeList.begin(); ni != myNodeList.end(); ++ni) {
      72       156879 :         if ((*ni)->samePos(xID, yID)) {
      73              :             return *ni;
      74              :         }
      75              :     }
      76              :     return nullptr;
      77              : }
      78              : 
      79              : std::string
      80          326 : NGNet::alphabeticalCode(int i, int iMax) {
      81              :     // lazy mans 26th root to determine number of characters for x-label
      82              :     int xn = 1;
      83          326 :     for (; std::pow(26, xn) < iMax; xn++) {};
      84          326 :     std::string result = "";
      85          652 :     for (int j = 0; j < xn; j++) {
      86          326 :         result = char('A' + (i % 26)) + result;
      87          326 :         i /= 26;
      88              :     }
      89          326 :     return result;
      90              : }
      91              : 
      92              : void
      93           44 : NGNet::createChequerBoard(int numX, int numY, double spaceX, double spaceY, double xAttachLength, double yAttachLength) {
      94              : 
      95          293 :     for (int ix = 0; ix < numX; ix++) {
      96          249 :         const std::string nodeIDStart = (myAlphaIDs ? alphabeticalCode(ix, numX) : toString<int>(ix) + "/");
      97         1890 :         for (int iy = 0; iy < numY; iy++) {
      98              :             // create Node
      99         1641 :             NGNode* node = new NGNode(nodeIDStart + toString(iy), ix, iy);
     100         1641 :             node->setX(ix * spaceX + xAttachLength);
     101         1641 :             node->setY(iy * spaceY + yAttachLength);
     102         1641 :             myNodeList.push_back(node);
     103              :             // create Links
     104         1641 :             if (ix > 0) {
     105         2850 :                 connect(findNode(ix - 1, iy), node);
     106              :             }
     107         1641 :             if (iy > 0) {
     108         2784 :                 connect(findNode(ix, iy - 1), node);
     109              :             }
     110              :         }
     111              :     }
     112           44 :     if (yAttachLength > 0.0) {
     113           14 :         for (int ix = 0; ix < numX; ix++) {
     114              :             // create nodes
     115           18 :             NGNode* topNode = new NGNode("top" + toString<int>(ix), ix, numY);
     116           18 :             NGNode* bottomNode = new NGNode("bottom" + toString<int>(ix), ix, numY + 1);
     117            9 :             topNode->setX(ix * spaceX + xAttachLength);
     118              :             bottomNode->setX(ix * spaceX + xAttachLength);
     119            9 :             topNode->setY((numY - 1) * spaceY + 2 * yAttachLength);
     120              :             bottomNode->setY(0);
     121              :             topNode->setFringe();
     122              :             bottomNode->setFringe();
     123            9 :             myNodeList.push_back(topNode);
     124              :             myNodeList.push_back(bottomNode);
     125              :             // create links
     126            9 :             connect(findNode(ix, numY - 1), topNode);
     127            9 :             connect(bottomNode, findNode(ix, 0));
     128              :         }
     129              :     }
     130           44 :     if (xAttachLength > 0.0) {
     131           14 :         for (int iy = 0; iy < numY; iy++) {
     132              :             // create nodes
     133           18 :             NGNode* leftNode = new NGNode("left" + toString<int>(iy), numX, iy);
     134           27 :             NGNode* rightNode = new NGNode("right" + toString<int>(iy), numX + 1, iy);
     135              :             leftNode->setX(0);
     136            9 :             rightNode->setX((numX - 1) * spaceX + 2 * xAttachLength);
     137            9 :             leftNode->setY(iy * spaceY + yAttachLength);
     138              :             rightNode->setY(iy * spaceY + yAttachLength);
     139              :             leftNode->setFringe();
     140              :             rightNode->setFringe();
     141            9 :             myNodeList.push_back(leftNode);
     142              :             myNodeList.push_back(rightNode);
     143              :             // create links
     144            9 :             connect(leftNode, findNode(0, iy));
     145            9 :             connect(findNode(numX - 1, iy), rightNode);
     146              :         }
     147              :     }
     148           44 : }
     149              : 
     150              : 
     151              : double
     152            0 : NGNet::radialToX(double radius, double phi) {
     153          631 :     return cos(phi) * radius;
     154              : }
     155              : 
     156              : 
     157              : double
     158            0 : NGNet::radialToY(double radius, double phi) {
     159          631 :     return sin(phi) * radius;
     160              : }
     161              : 
     162              : 
     163              : void
     164           20 : NGNet::createSpiderWeb(int numRadDiv, int numCircles, double spaceRad, bool hasCenter, double attachLength) {
     165           20 :     if (numRadDiv < 3) {
     166              :         numRadDiv = 3;
     167              :     }
     168           20 :     if (numCircles < 1) {
     169              :         numCircles = 1;
     170              :     }
     171              : 
     172              :     int ir, ic;
     173           20 :     double angle = (double)(2 * M_PI / numRadDiv); // angle between radial divisions
     174              :     NGNode* node;
     175              :     int attachCircle = -1;
     176           20 :     if (attachLength > 0) {
     177            1 :         numCircles += 1;
     178              :         attachCircle = numCircles;
     179              :     }
     180          100 :     for (ic = 1; ic < numCircles + 1; ic++) {
     181           80 :         const std::string nodeIDStart = alphabeticalCode(ic, numCircles);
     182           80 :         if (ic == attachCircle) {
     183              :             spaceRad = attachLength;
     184              :         }
     185          711 :         for (ir = 1; ir < numRadDiv + 1; ir++) {
     186              :             // create Node
     187          631 :             const std::string nodeID = (myAlphaIDs ?
     188          619 :                                         nodeIDStart + toString<int>(ir) :
     189          679 :                                         toString<int>(ir) + "/" + toString<int>(ic));
     190          631 :             node = new NGNode(nodeID, ir, ic);
     191          631 :             node->setX(radialToX((ic) * spaceRad, (ir - 1) * angle));
     192              :             node->setY(radialToY((ic) * spaceRad, (ir - 1) * angle));
     193          631 :             myNodeList.push_back(node);
     194              :             // create Links
     195          631 :             if (ir > 1 && ic != attachCircle) {
     196          545 :                 connect(findNode(ir - 1, ic), node);
     197              :             }
     198          631 :             if (ic > 1) {
     199         1020 :                 connect(findNode(ir, ic - 1), node);
     200              :             }
     201          631 :             if (ir == numRadDiv && ic != attachCircle) {
     202           79 :                 connect(node, findNode(1, ic));
     203              :             }
     204              :         }
     205              :     }
     206           20 :     if (hasCenter) {
     207              :         // node
     208           18 :         node = new NGNode(myAlphaIDs ? "A1" : "1", 0, 0, true);
     209              :         node->setX(0);
     210              :         node->setY(0);
     211           17 :         myNodeList.push_back(node);
     212              :         // links
     213          117 :         for (ir = 1; ir < numRadDiv + 1; ir++) {
     214          100 :             connect(node, findNode(ir, 1));
     215              :         }
     216              :     }
     217           20 : }
     218              : 
     219              : 
     220              : void
     221         4087 : NGNet::connect(NGNode* node1, NGNode* node2) {
     222         4123 :     std::string id1 = node1->getID() + (myAlphaIDs ? "" : "to") + node2->getID();
     223         4123 :     std::string id2 = node2->getID() + (myAlphaIDs ? "" : "to") + node1->getID();
     224         4087 :     NGEdge* link1 = new NGEdge(id1, node1, node2, id2);
     225         4087 :     myEdgeList.push_back(link1);
     226         4087 : }
     227              : 
     228              : Distribution_Parameterized
     229          264 : NGNet::getDistribution(const std::string& option) {
     230          264 :     const std::string& val = OptionsCont::getOptions().getString(option);
     231              :     try {
     232          264 :         return Distribution_Parameterized(option, 0, StringUtils::toDouble(val));
     233            2 :     } catch (NumberFormatException&) {
     234            2 :         return Distribution_Parameterized(val);
     235            2 :     }
     236              : }
     237              : 
     238              : 
     239              : void
     240           88 : NGNet::toNB() const {
     241           88 :     Distribution_Parameterized perturbx = getDistribution("perturb-x");
     242           88 :     Distribution_Parameterized perturby = getDistribution("perturb-y");
     243          176 :     Distribution_Parameterized perturbz = getDistribution("perturb-z");
     244         5435 :     for (const NGNode* const ngNode : myNodeList) {
     245              :         // we need to sample in separate instructions because evaluation order is compiler dependent
     246         5347 :         Position perturb(perturbx.sample(), 0.);
     247         5347 :         perturb.sety(perturby.sample());
     248         5347 :         perturb.setz(perturbz.sample());
     249         5347 :         myNetBuilder.getNodeCont().insert(ngNode->buildNBNode(myNetBuilder, perturb));
     250              :     }
     251           88 :     const std::string type = OptionsCont::getOptions().getString("default.type");
     252          176 :     const double bidiProb = OptionsCont::getOptions().getFloat("bidi-probability");
     253         8353 :     for (const NGEdge* const ngEdge : myEdgeList) {
     254        24795 :         myNetBuilder.getEdgeCont().insert(ngEdge->buildNBEdge(myNetBuilder, type));
     255              :         // now, let's append the reverse directions...
     256         8265 :         if (!ngEdge->getEndNode()->connected(ngEdge->getStartNode(), true) && RandHelper::rand() <= bidiProb) {
     257        20679 :             myNetBuilder.getEdgeCont().insert(ngEdge->buildNBEdge(myNetBuilder, type, true));
     258              :         }
     259              :     }
     260              :     // add splits depending on turn-lane options
     261           88 :     const int turnLanes = OptionsCont::getOptions().getInt("turn-lanes");
     262           88 :     const bool lefthand =  OptionsCont::getOptions().getBool("lefthand");
     263           88 :     if (turnLanes > 0) {
     264            4 :         const double turnLaneLength = OptionsCont::getOptions().getFloat("turn-lanes.length");
     265            4 :         NBEdgeCont& ec = myNetBuilder.getEdgeCont();
     266              :         EdgeVector allEdges;
     267          142 :         for (auto it = ec.begin(); it != ec.end(); ++it) {
     268          138 :             allEdges.push_back(it->second);
     269              :         }
     270          142 :         for (NBEdge* e : allEdges) {
     271          138 :             if (e->getToNode()->geometryLike()) {
     272           31 :                 continue;
     273              :             }
     274              :             std::vector<NBEdgeCont::Split> splits;
     275              :             NBEdgeCont::Split split;
     276          391 :             for (int i = 0; i < e->getNumLanes() + turnLanes; ++i) {
     277          284 :                 split.lanes.push_back(i);
     278              :             }
     279          107 :             split.pos = MAX2(0.0, e->getLength() - turnLaneLength);
     280          107 :             split.speed = e->getSpeed();
     281          214 :             split.node = new NBNode(e->getID() + "." + toString(split.pos), e->getGeometry().positionAtOffset(split.pos));
     282          107 :             split.idBefore = e->getID();
     283          107 :             split.idAfter = split.node->getID();
     284          107 :             split.offsetFactor = lefthand ? -1 : 1;
     285          107 :             if (turnLaneLength <= e->getLength() / 2) {
     286          107 :                 split.offset = -0.5 * split.offsetFactor * turnLanes * e->getLaneWidth(0);
     287          107 :                 if (e->getFromNode()->geometryLike()) {
     288              :                     // shift the reverse direction explicitly as it will not get a turn lane
     289              :                     NBEdge* reverse = nullptr;
     290           88 :                     for (NBEdge* reverseCand : e->getFromNode()->getIncomingEdges()) {
     291           57 :                         if (reverseCand->getFromNode() == e->getToNode()) {
     292              :                             reverse = reverseCand;
     293              :                         }
     294              :                     }
     295           31 :                     if (reverse != nullptr) {
     296              :                         PositionVector g = reverse->getGeometry();
     297           31 :                         g.move2side(-split.offset);
     298           31 :                         reverse->setGeometry(g);
     299           31 :                     }
     300              :                 }
     301              :             }
     302          107 :             splits.push_back(split);
     303          107 :             ec.processSplits(e, splits,
     304              :                              myNetBuilder.getNodeCont(),
     305              :                              myNetBuilder.getDistrictCont(),
     306          107 :                              myNetBuilder.getTLLogicCont());
     307          107 :         }
     308            4 :     }
     309           88 : }
     310              : 
     311              : 
     312              : void
     313         3022 : NGNet::add(NGNode* node) {
     314         3022 :     myNodeList.push_back(node);
     315         3022 : }
     316              : 
     317              : 
     318              : void
     319         4178 : NGNet::add(NGEdge* edge) {
     320         4178 :     myEdgeList.push_back(edge);
     321         4178 : }
     322              : 
     323              : 
     324              : int
     325        11764 : NGNet::nodeNo() const {
     326        11764 :     return (int)myNodeList.size();
     327              : }
     328              : 
     329              : 
     330              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1