LCOV - code coverage report
Current view: top level - src/netgen - NGNet.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 148 151 98.0 %
Date: 2024-09-16 15:39:55 Functions: 12 15 80.0 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2003-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    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          91 : NGNet::NGNet(NBNetBuilder& nb) :
      47          91 :     myLastID(0),
      48          91 :     myAlphaIDs(OptionsCont::getOptions().getBool("alphanumerical-ids")),
      49          91 :     myNetBuilder(nb) {
      50          91 : }
      51             : 
      52             : 
      53          91 : NGNet::~NGNet() {
      54        8652 :     for (NGEdgeList::iterator ni = myEdgeList.begin(); ni != myEdgeList.end(); ++ni) {
      55        8561 :         delete *ni;
      56             :     }
      57        5608 :     for (NGNodeList::iterator ni = myNodeList.begin(); ni != myNodeList.end(); ++ni) {
      58        5517 :         delete *ni;
      59             :     }
      60          91 : }
      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      166850 :     for (NGNodeList::iterator ni = myNodeList.begin(); ni != myNodeList.end(); ++ni) {
      72      166850 :         if ((*ni)->samePos(xID, yID)) {
      73             :             return *ni;
      74             :         }
      75             :     }
      76             :     return nullptr;
      77             : }
      78             : 
      79             : std::string
      80         350 : NGNet::alphabeticalCode(int i, int iMax) {
      81             :     // lazy mans 26th root to determine number of characters for x-label
      82             :     int xn = 1;
      83         350 :     for (; std::pow(26, xn) < iMax; xn++) {};
      84         350 :     std::string result = "";
      85         700 :     for (int j = 0; j < xn; j++) {
      86         350 :         result = char('A' + (i % 26)) + result;
      87         350 :         i /= 26;
      88             :     }
      89         350 :     return result;
      90             : }
      91             : 
      92             : void
      93          47 : NGNet::createChequerBoard(int numX, int numY, double spaceX, double spaceY, double xAttachLength, double yAttachLength) {
      94             : 
      95         320 :     for (int ix = 0; ix < numX; ix++) {
      96         273 :         const std::string nodeIDStart = (myAlphaIDs ? alphabeticalCode(ix, numX) : toString<int>(ix) + "/");
      97        2088 :         for (int iy = 0; iy < numY; iy++) {
      98             :             // create Node
      99        1815 :             NGNode* node = new NGNode(nodeIDStart + toString(iy), ix, iy);
     100        1815 :             node->setX(ix * spaceX + xAttachLength);
     101        1815 :             node->setY(iy * spaceY + yAttachLength);
     102        1815 :             myNodeList.push_back(node);
     103             :             // create Links
     104        1815 :             if (ix > 0) {
     105        3150 :                 connect(findNode(ix - 1, iy), node);
     106             :             }
     107        1815 :             if (iy > 0) {
     108        3084 :                 connect(findNode(ix, iy - 1), node);
     109             :             }
     110             :         }
     111             :     }
     112          47 :     if (yAttachLength > 0.0) {
     113          12 :         for (int ix = 0; ix < numX; ix++) {
     114             :             // create nodes
     115           8 :             NGNode* topNode = new NGNode("top" + toString<int>(ix), ix, numY);
     116           8 :             NGNode* bottomNode = new NGNode("bottom" + toString<int>(ix), ix, numY + 1);
     117           8 :             topNode->setX(ix * spaceX + xAttachLength);
     118             :             bottomNode->setX(ix * spaceX + xAttachLength);
     119           8 :             topNode->setY((numY - 1) * spaceY + 2 * yAttachLength);
     120             :             bottomNode->setY(0);
     121             :             topNode->setFringe();
     122             :             bottomNode->setFringe();
     123           8 :             myNodeList.push_back(topNode);
     124             :             myNodeList.push_back(bottomNode);
     125             :             // create links
     126          16 :             connect(findNode(ix, numY - 1), topNode);
     127          16 :             connect(bottomNode, findNode(ix, 0));
     128             :         }
     129             :     }
     130          47 :     if (xAttachLength > 0.0) {
     131          12 :         for (int iy = 0; iy < numY; iy++) {
     132             :             // create nodes
     133           8 :             NGNode* leftNode = new NGNode("left" + toString<int>(iy), numX, iy);
     134           8 :             NGNode* rightNode = new NGNode("right" + toString<int>(iy), numX + 1, iy);
     135             :             leftNode->setX(0);
     136           8 :             rightNode->setX((numX - 1) * spaceX + 2 * xAttachLength);
     137           8 :             leftNode->setY(iy * spaceY + yAttachLength);
     138             :             rightNode->setY(iy * spaceY + yAttachLength);
     139             :             leftNode->setFringe();
     140             :             rightNode->setFringe();
     141           8 :             myNodeList.push_back(leftNode);
     142             :             myNodeList.push_back(rightNode);
     143             :             // create links
     144          16 :             connect(leftNode, findNode(0, iy));
     145          16 :             connect(findNode(numX - 1, iy), rightNode);
     146             :         }
     147             :     }
     148          47 : }
     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             :     if (numRadDiv < 3) {
     166             :         numRadDiv = 3;
     167             :     }
     168             :     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        1286 :                                         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        1090 :                 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        4383 : NGNet::connect(NGNode* node1, NGNode* node2) {
     222        4419 :     std::string id1 = node1->getID() + (myAlphaIDs ? "" : "to") + node2->getID();
     223        4419 :     std::string id2 = node2->getID() + (myAlphaIDs ? "" : "to") + node1->getID();
     224        4383 :     NGEdge* link1 = new NGEdge(id1, node1, node2, id2);
     225        4383 :     myEdgeList.push_back(link1);
     226        4383 : }
     227             : 
     228             : Distribution_Parameterized
     229         273 : NGNet::getDistribution(const std::string& option) {
     230         273 :     const std::string& val = OptionsCont::getOptions().getString(option);
     231             :     try {
     232         273 :         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          91 : NGNet::toNB() const {
     241          91 :     Distribution_Parameterized perturbx = getDistribution("perturb-x");
     242          91 :     Distribution_Parameterized perturby = getDistribution("perturb-y");
     243         182 :     Distribution_Parameterized perturbz = getDistribution("perturb-z");
     244        5608 :     for (const NGNode* const ngNode : myNodeList) {
     245             :         // we need to sample in separate instructions because evaluation order is compiler dependent
     246        5517 :         Position perturb(perturbx.sample(), 0.);
     247        5517 :         perturb.sety(perturby.sample());
     248        5517 :         perturb.setz(perturbz.sample());
     249        5517 :         myNetBuilder.getNodeCont().insert(ngNode->buildNBNode(myNetBuilder, perturb));
     250             :     }
     251          91 :     const std::string type = OptionsCont::getOptions().getString("default.type");
     252         182 :     const double bidiProb = OptionsCont::getOptions().getFloat("bidi-probability");
     253        8652 :     for (const NGEdge* const ngEdge : myEdgeList) {
     254       25683 :         myNetBuilder.getEdgeCont().insert(ngEdge->buildNBEdge(myNetBuilder, type));
     255             :         // now, let's append the reverse directions...
     256        8561 :         if (!ngEdge->getEndNode()->connected(ngEdge->getStartNode(), true) && RandHelper::rand() <= bidiProb) {
     257       21567 :             myNetBuilder.getEdgeCont().insert(ngEdge->buildNBEdge(myNetBuilder, type, true));
     258             :         }
     259             :     }
     260             :     // add splits depending on turn-lane options
     261          91 :     const int turnLanes = OptionsCont::getOptions().getInt("turn-lanes");
     262          91 :     const bool lefthand =  OptionsCont::getOptions().getBool("lefthand");
     263          91 :     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         107 :             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             :     }
     309          91 : }
     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 1.14