LCOV - code coverage report
Current view: top level - src/netgen - netgen_main.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 93.3 % 165 154
Test Date: 2025-12-06 15:35:27 Functions: 100.0 % 4 4

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-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    netgen_main.cpp
      15              : /// @author  Markus Hartinger
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Jakob Erdmann
      18              : /// @author  Michael Behrisch
      19              : /// @date    Mar, 2003
      20              : ///
      21              : // Main for NETGENERATE
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #ifdef HAVE_VERSION_H
      26              : #include <version.h>
      27              : #endif
      28              : 
      29              : #include <iostream>
      30              : #include <fstream>
      31              : #include <string>
      32              : #include <ctime>
      33              : #include <netgen/NGNet.h>
      34              : #include <netgen/NGRandomNetBuilder.h>
      35              : #include <netgen/NGFrame.h>
      36              : #include <netbuild/NBNetBuilder.h>
      37              : #include <netbuild/NBFrame.h>
      38              : #include <netwrite/NWFrame.h>
      39              : #include <netimport/NITypeLoader.h>
      40              : #include <netimport/NIXMLTypesHandler.h>
      41              : #include <utils/options/OptionsCont.h>
      42              : #include <utils/options/OptionsIO.h>
      43              : #include <utils/options/Option.h>
      44              : #include <utils/common/MsgHandler.h>
      45              : #include <utils/common/SystemFrame.h>
      46              : #include <utils/common/UtilExceptions.h>
      47              : #include <utils/common/RandHelper.h>
      48              : #include <utils/common/ToString.h>
      49              : #include <utils/distribution/RandomDistributor.h>
      50              : #include <utils/geom/GeoConvHelper.h>
      51              : #include <utils/xml/XMLSubSys.h>
      52              : #include <utils/iodevices/OutputDevice.h>
      53              : 
      54              : 
      55              : // ===========================================================================
      56              : // method definitions
      57              : // ===========================================================================
      58              : void
      59          120 : fillOptions() {
      60          120 :     OptionsCont& oc = OptionsCont::getOptions();
      61          240 :     oc.addCallExample("-c <CONFIGURATION>", TL("create net from given configuration"));
      62          240 :     oc.addCallExample("--grid [grid-network options] -o <OUTPUTFILE>", TL("create grid net"));
      63          240 :     oc.addCallExample("--spider [spider-network options] -o <OUTPUTFILE>", TL("create spider net"));
      64          240 :     oc.addCallExample("--rand [random-network options] -o <OUTPUTFILE>", TL("create random net"));
      65              : 
      66          120 :     oc.setAdditionalHelpMessage(" Either \"--grid\", \"--spider\" or \"--rand\" must be supplied.\n  In dependence to these switches other options are used.");
      67              : 
      68              :     // insert options sub-topics
      69          120 :     SystemFrame::addConfigurationOptions(oc); // this subtopic is filled here, too
      70          120 :     oc.addOptionSubTopic("Grid Network");
      71          120 :     oc.addOptionSubTopic("Spider Network");
      72          120 :     oc.addOptionSubTopic("Random Network");
      73          120 :     oc.addOptionSubTopic("Input");
      74          120 :     oc.addOptionSubTopic("Output");
      75          120 :     oc.addOptionSubTopic("Processing");
      76          120 :     oc.addOptionSubTopic("Building Defaults");
      77          120 :     oc.addOptionSubTopic("TLS Building");
      78          120 :     oc.addOptionSubTopic("Edge Removal");
      79          120 :     oc.addOptionSubTopic("Unregulated Nodes");
      80          120 :     oc.addOptionSubTopic("Junctions");
      81          120 :     oc.addOptionSubTopic("Pedestrian");
      82          120 :     oc.addOptionSubTopic("Bicycle");
      83          120 :     SystemFrame::addReportOptions(oc); // this subtopic is filled here, too
      84              : 
      85          120 :     NGFrame::fillOptions();
      86          120 :     NBFrame::fillOptions(oc, true);
      87          120 :     NWFrame::fillOptions(oc, true);
      88          120 :     oc.doRegister("default-junction-type", 'j', new Option_String());
      89          240 :     oc.addSynonyme("default-junction-type", "junctions");
      90          240 :     oc.addDescription("default-junction-type", "Building Defaults", TL("[traffic_light|priority|right_before_left|left_before_right|traffic_light_right_on_red|priority_stop|allway_stop|...] Determines junction type (see wiki/Networks/PlainXML#Node_types)"));
      91          120 :     RandHelper::insertRandOptions(oc);
      92              : 
      93          120 :     oc.doRegister("tls.discard-simple", new Option_Bool(false));
      94          240 :     oc.addDescription("tls.discard-simple", "TLS Building", "Does not instantiate traffic lights at geometry-like nodes");
      95              : 
      96          240 :     oc.doRegister("railway.signal.permit-unsignalized", new Option_StringVector({"tram", "cable_car"}));
      97          240 :     oc.addDescription("railway.signal.permit-unsignalized", "TLS Building", TL("List rail classes that may run without rail signals"));
      98          120 : }
      99              : 
     100              : 
     101              : bool
     102          112 : checkOptions() {
     103          112 :     OptionsCont& oc = OptionsCont::getOptions();
     104          112 :     bool ok = NGFrame::checkOptions();
     105          112 :     ok &= NBFrame::checkOptions(oc);
     106          112 :     ok &= NWFrame::checkOptions(oc);
     107          112 :     ok &= SystemFrame::checkOptions(oc);
     108          112 :     return ok;
     109              : }
     110              : 
     111              : 
     112              : NGNet*
     113          100 : buildNetwork(NBNetBuilder& nb) {
     114          100 :     OptionsCont& oc = OptionsCont::getOptions();
     115              : 
     116          101 :     const double laneWidth = oc.isDefault("default.lanewidth") ? SUMO_const_laneWidth : oc.getFloat("default.lanewidth");
     117          100 :     double minLength = (oc.getInt("default.lanenumber") + oc.getInt("turn-lanes")) * 2 * laneWidth + oc.getFloat("default.junctions.radius") * 2 + POSITION_EPS;
     118              :     // spider-net
     119          200 :     if (oc.getBool("spider")) {
     120              :         // check values
     121              :         bool hadError = false;
     122           46 :         if (oc.getInt("spider.arm-number") < 3) {
     123            2 :             WRITE_ERROR(TL("Spider networks need at least 3 arms."));
     124              :             hadError = true;
     125              :         }
     126           40 :         if (oc.getInt("spider.arm-number") > 4 && !oc.getBool("spider.omit-center")) {
     127           22 :             WRITE_WARNING(TL("Spider networks with many arms should use option spider.omit-center"));
     128              :         }
     129           46 :         if (oc.getInt("spider.circle-number") < 1) {
     130            4 :             WRITE_ERROR(TL("Spider networks need at least one circle."));
     131              :             hadError = true;
     132              :         }
     133           23 :         minLength = MAX2(minLength, laneWidth * 2 * MAX2(oc.getInt("spider.arm-number"), 3) / (2 * M_PI));
     134           46 :         if (oc.getFloat("spider.space-radius") < POSITION_EPS) {
     135            0 :             WRITE_ERROR("The radius of spider networks must be at least "  + toString(POSITION_EPS));
     136              :             hadError = true;
     137           46 :         } else if (oc.getFloat("spider.space-radius") < minLength) {
     138            2 :             WRITE_WARNINGF(TL("The radius of spider networks should be at least % for the given lanenumber, lanewidth and junction radius"), toString(minLength));
     139              :         }
     140           23 :         if (hadError) {
     141            3 :             throw ProcessError();
     142              :         }
     143              :         // build if everything's ok
     144           20 :         NGNet* net = new NGNet(nb);
     145           60 :         net->createSpiderWeb(oc.getInt("spider.arm-number"), oc.getInt("spider.circle-number"),
     146           40 :                              oc.getFloat("spider.space-radius"), !oc.getBool("spider.omit-center"),
     147              :                              oc.getFloat("spider.attach-length"));
     148           20 :         return net;
     149              :     }
     150              :     // grid-net
     151          154 :     if (oc.getBool("grid")) {
     152              :         // get options
     153           53 :         int xNo = oc.getInt("grid.x-number");
     154           53 :         int yNo = oc.getInt("grid.y-number");
     155           53 :         double xLength = oc.getFloat("grid.x-length");
     156           53 :         double yLength = oc.getFloat("grid.y-length");
     157           53 :         double xAttachLength = oc.getFloat("grid.x-attach-length");
     158           53 :         double yAttachLength = oc.getFloat("grid.y-attach-length");
     159           98 :         if (oc.isDefault("grid.x-number") && !oc.isDefault("grid.number")) {
     160           62 :             xNo = oc.getInt("grid.number");
     161              :         }
     162           98 :         if (oc.isDefault("grid.y-number") && !oc.isDefault("grid.number")) {
     163           62 :             yNo = oc.getInt("grid.number");
     164              :         }
     165          112 :         if (oc.isDefault("grid.x-length") && !oc.isDefault("grid.length")) {
     166           62 :             xLength = oc.getFloat("grid.length");
     167              :         }
     168          112 :         if (oc.isDefault("grid.y-length") && !oc.isDefault("grid.length")) {
     169           62 :             yLength = oc.getFloat("grid.length");
     170              :         }
     171          153 :         if (oc.isDefault("grid.x-attach-length") && !oc.isDefault("grid.attach-length")) {
     172            8 :             xAttachLength = oc.getFloat("grid.attach-length");
     173              :         }
     174          153 :         if (oc.isDefault("grid.y-attach-length") && !oc.isDefault("grid.attach-length")) {
     175            8 :             yAttachLength = oc.getFloat("grid.attach-length");
     176              :         }
     177              :         // check values
     178              :         bool hadError = false;
     179           53 :         if (xNo < 1 || yNo < 1 || (xAttachLength == 0 && yAttachLength == 0 && (xNo < 2 && yNo < 2))) {
     180           12 :             WRITE_ERROR(TL("The number of nodes must be positive and at least 2 in one direction if there are no attachments."));
     181              :             hadError = true;
     182              :         }
     183           53 :         const double minAttachLength = minLength / 2 + POSITION_EPS / 2;
     184           53 :         if (xLength < POSITION_EPS || yLength < POSITION_EPS) {
     185            6 :             WRITE_ERROR("The distance between nodes must be at least " + toString(POSITION_EPS));
     186            3 :             hadError = true;
     187           50 :         } else if (xLength < minLength || yLength < minLength) {
     188            8 :             WRITE_WARNINGF(TL("The distance between nodes should be at least % for the given lanenumber, lanewidth and junction radius"), toString(minLength));
     189              :         }
     190           53 :         if (xAttachLength != 0.0 && xAttachLength < POSITION_EPS) {
     191            0 :             WRITE_ERROR("The length of attached streets must be at least " + toString(POSITION_EPS));
     192              :             hadError = true;
     193            5 :         } else if (xAttachLength != 0.0 && xAttachLength < minAttachLength) {
     194            0 :             WRITE_WARNINGF(TL("The length of attached streets should be at least % for the given lanenumber, lanewidth and junction radius"), toString(minAttachLength));
     195           53 :         } else if (yAttachLength != 0.0 && yAttachLength < POSITION_EPS) {
     196            0 :             WRITE_ERROR("The length of attached streets must be at least " + toString(POSITION_EPS));
     197              :             hadError = true;
     198            5 :         } else if (yAttachLength != 0.0 && yAttachLength < minAttachLength) {
     199            0 :             WRITE_WARNINGF(TL("The length of attached streets should be at least % for the given lanenumber, lanewidth and junction radius"), toString(minAttachLength));
     200              :         }
     201           53 :         if (hadError) {
     202            9 :             throw ProcessError();
     203              :         }
     204              :         // build if everything's ok
     205           44 :         NGNet* net = new NGNet(nb);
     206           44 :         net->createChequerBoard(xNo, yNo, xLength, yLength, xAttachLength, yAttachLength);
     207              :         return net;
     208              :     }
     209              :     // random net
     210              :     RandomDistributor<int> neighborDist;
     211           24 :     neighborDist.add(1, oc.getFloat("rand.neighbor-dist1"));
     212           24 :     neighborDist.add(2, oc.getFloat("rand.neighbor-dist2"));
     213           24 :     neighborDist.add(3, oc.getFloat("rand.neighbor-dist3"));
     214           24 :     neighborDist.add(4, oc.getFloat("rand.neighbor-dist4"));
     215           24 :     neighborDist.add(5, oc.getFloat("rand.neighbor-dist5"));
     216           24 :     neighborDist.add(6, oc.getFloat("rand.neighbor-dist6"));
     217           24 :     NGNet* net = new NGNet(nb);
     218              :     NGRandomNetBuilder randomNet(*net,
     219           48 :                                  DEG2RAD(oc.getFloat("rand.min-angle")),
     220              :                                  oc.getFloat("rand.min-distance"),
     221              :                                  oc.getFloat("rand.max-distance"),
     222              :                                  oc.getFloat("rand.connectivity"),
     223              :                                  oc.getInt("rand.num-tries"),
     224           72 :                                  neighborDist);
     225           48 :     randomNet.createNet(oc.getInt("rand.iterations"), oc.getBool("rand.grid"));
     226              :     return net;
     227           24 : }
     228              : 
     229              : 
     230              : 
     231              : int
     232          120 : main(int argc, char** argv) {
     233          120 :     OptionsCont& oc = OptionsCont::getOptions();
     234          120 :     oc.setApplicationDescription(TL("Synthetic network generator for the microscopic, multi-modal traffic simulation SUMO."));
     235          240 :     oc.setApplicationName("netgenerate", "Eclipse SUMO netgenerate " VERSION_STRING);
     236              :     int ret = 0;
     237              :     try {
     238              :         // initialise the application system (messaging, xml, options)
     239          120 :         XMLSubSys::init();
     240          120 :         fillOptions();
     241          120 :         OptionsIO::setArgs(argc, argv);
     242          120 :         OptionsIO::getOptions();
     243          119 :         if (oc.processMetaOptions(argc < 2)) {
     244            7 :             SystemFrame::close();
     245            7 :             return 0;
     246              :         }
     247          224 :         XMLSubSys::setValidation(oc.getString("xml-validation"), "never", "never");
     248          112 :         MsgHandler::initOutputOptions();
     249          112 :         if (!checkOptions()) {
     250           12 :             throw ProcessError();
     251              :         }
     252          200 :         GeoConvHelper::init("!",
     253          200 :                             Position(oc.getFloat("offset.x"), oc.getFloat("offset.y")),
     254          100 :                             Boundary(), Boundary());
     255          100 :         RandHelper::initRandGlobal();
     256          100 :         NBNetBuilder nb;
     257          100 :         nb.applyOptions(oc);
     258          200 :         if (oc.isSet("type-files")) {
     259            3 :             NIXMLTypesHandler handler(nb.getTypeCont());
     260            6 :             NITypeLoader::load(handler, oc.getStringVector("type-files"), toString(SUMO_TAG_TYPES));
     261            3 :         }
     262              :         // build the netgen-network description
     263          100 :         NGNet* net = buildNetwork(nb);
     264              :         // ... and we have to do this...
     265           88 :         oc.resetWritable();
     266              :         // transfer to the netbuilding structures
     267           88 :         net->toNB();
     268           88 :         delete net;
     269              :         // report generated structures
     270           88 :         WRITE_MESSAGE(TL(" Generation done;"));
     271          176 :         WRITE_MESSAGEF(TL("   % nodes generated."), toString<int>(nb.getNodeCont().size()));
     272          176 :         WRITE_MESSAGEF(TL("   % edges generated."), toString<int>(nb.getEdgeCont().size()));
     273          176 :         if (oc.getBool("tls.discard-simple")) {
     274            1 :             nb.getNodeCont().discardTrafficLights(nb.getTLLogicCont(), true);
     275            1 :             int removed = nb.getTLLogicCont().getNumExtracted();
     276            1 :             if (removed > 0) {
     277            2 :                 WRITE_MESSAGEF(TL(" Removed % traffic lights at geometry-like nodes"), toString(removed));
     278              :             }
     279              :         }
     280           88 :         nb.compute(oc);
     281           88 :         nb.getNodeCont().printBuiltNodesStatistics();
     282           88 :         NWFrame::writeNetwork(oc, nb);
     283          128 :     } catch (const ProcessError& e) {
     284           36 :         if (std::string(e.what()) != std::string("Process Error") && std::string(e.what()) != std::string("")) {
     285            8 :             WRITE_ERROR(e.what());
     286              :         }
     287           28 :         MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
     288              :         ret = 1;
     289              : #ifndef _DEBUG
     290           28 :     } catch (const std::exception& e) {
     291            0 :         if (std::string(e.what()) != std::string("")) {
     292            0 :             WRITE_ERROR(e.what());
     293              :         }
     294            0 :         MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
     295              :         ret = 1;
     296            0 :     } catch (...) {
     297            0 :         MsgHandler::getErrorInstance()->inform("Quitting (on unknown error).", false);
     298              :         ret = 1;
     299              : #endif
     300            0 :     }
     301          113 :     SystemFrame::close();
     302              :     if (ret == 0) {
     303              :         std::cout << "Success." << std::endl;
     304              :     }
     305              :     return ret;
     306              : }
     307              : 
     308              : 
     309              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1