LCOV - code coverage report
Current view: top level - src/netgen - netgen_main.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 152 163 93.3 %
Date: 2024-09-16 15:39:55 Functions: 4 4 100.0 %

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

Generated by: LCOV version 1.14