LCOV - code coverage report
Current view: top level - src/netload - NLTriggerBuilder.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 81.3 % 503 409
Test Date: 2024-12-21 15:45:41 Functions: 97.3 % 37 36

            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    NLTriggerBuilder.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Tino Morenz
      17              : /// @author  Jakob Erdmann
      18              : /// @author  Eric Nicolay
      19              : /// @author  Sascha Krieg
      20              : /// @author  Michael Behrisch
      21              : /// @author  Johannes Rummel
      22              : /// @date    Thu, 17 Oct 2002
      23              : ///
      24              : // Builds trigger objects for microsim
      25              : /****************************************************************************/
      26              : #include <config.h>
      27              : 
      28              : #include <string>
      29              : #include <mesosim/MELoop.h>
      30              : #include <mesosim/METriggeredCalibrator.h>
      31              : #include <microsim/MSEventControl.h>
      32              : #include <microsim/MSJunctionControl.h>
      33              : #include <microsim/MSLane.h>
      34              : #include <microsim/MSEdge.h>
      35              : #include <microsim/MSGlobals.h>
      36              : #include <microsim/MSParkingArea.h>
      37              : #include <microsim/MSStoppingPlace.h>
      38              : #include <microsim/output/MSDetectorControl.h>
      39              : #include <microsim/output/MSRouteProbe.h>
      40              : #include <microsim/trigger/MSLaneSpeedTrigger.h>
      41              : #include <microsim/trigger/MSTriggeredRerouter.h>
      42              : #include <microsim/trigger/MSCalibrator.h>
      43              : #include <microsim/trigger/MSChargingStation.h>
      44              : #include <microsim/trigger/MSOverheadWire.h>
      45              : #include <utils/common/StringTokenizer.h>
      46              : #include <utils/common/FileHelpers.h>
      47              : #include <utils/common/UtilExceptions.h>
      48              : #include <utils/common/WrappingCommand.h>
      49              : #include <utils/common/RGBColor.h>
      50              : #include <utils/options/OptionsCont.h>
      51              : #include <utils/xml/SUMOXMLDefinitions.h>
      52              : #include <utils/xml/XMLSubSys.h>
      53              : #include "NLHandler.h"
      54              : #include "NLTriggerBuilder.h"
      55              : 
      56              : 
      57              : // ===========================================================================
      58              : // method definitions
      59              : // ===========================================================================
      60        43238 : NLTriggerBuilder::NLTriggerBuilder()
      61        43238 :     : myHandler(nullptr), myParkingArea(nullptr), myCurrentStop(nullptr) {}
      62              : 
      63              : 
      64        43238 : NLTriggerBuilder::~NLTriggerBuilder() {}
      65              : 
      66              : void
      67        43238 : NLTriggerBuilder::setHandler(NLHandler* handler) {
      68        43238 :     myHandler = handler;
      69        43238 : }
      70              : 
      71              : 
      72              : void
      73          542 : NLTriggerBuilder::buildVaporizer(const SUMOSAXAttributes& attrs) {
      74          542 :     WRITE_WARNING(TL("Vaporizers are deprecated. Use rerouters instead."));
      75          542 :     bool ok = true;
      76              :     // get the id, throw if not given or empty...
      77          542 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
      78          542 :     if (!ok) {
      79              :         return;
      80              :     }
      81          530 :     MSEdge* e = MSEdge::dictionary(id);
      82          530 :     if (e == nullptr) {
      83           18 :         WRITE_ERRORF(TL("Unknown edge ('%') referenced in a vaporizer."), id);
      84            6 :         return;
      85              :     }
      86          524 :     SUMOTime begin = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok);
      87          524 :     SUMOTime end = attrs.getSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok);
      88          524 :     if (!ok) {
      89              :         return;
      90              :     }
      91          488 :     if (begin < 0) {
      92           18 :         WRITE_ERRORF(TL("A vaporization begin time is negative (edge id='%')."), id);
      93            6 :         return;
      94              :     }
      95          482 :     if (begin >= end) {
      96           36 :         WRITE_ERRORF(TL("A vaporization ends before it starts (edge id='%')."), id);
      97           12 :         return;
      98              :     }
      99          940 :     if (end >= string2time(OptionsCont::getOptions().getString("begin"))) {
     100          470 :         Command* cb = new WrappingCommand< MSEdge >(e, &MSEdge::incVaporization);
     101          470 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(cb, begin);
     102          470 :         Command* ce = new WrappingCommand< MSEdge >(e, &MSEdge::decVaporization);
     103          470 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(ce, end);
     104              :     }
     105              : }
     106              : 
     107              : 
     108              : void
     109          507 : NLTriggerBuilder::parseAndBuildLaneSpeedTrigger(MSNet& net, const SUMOSAXAttributes& attrs,
     110              :         const std::string& base) {
     111              :     // get the id, throw if not given or empty...
     112          507 :     bool ok = true;
     113              :     // get the id, throw if not given or empty...
     114          507 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     115          507 :     if (!ok) {
     116              :         return;
     117              :     }
     118              :     // get the file name to read further definitions from
     119          507 :     std::string file = getFileName(attrs, base, true);
     120          507 :     std::string objectid = attrs.get<std::string>(SUMO_ATTR_LANES, id.c_str(), ok);
     121              :     std::vector<MSLane*> lanes;
     122         1068 :     for (const std::string& laneID : attrs.get<std::vector<std::string> >(SUMO_ATTR_LANES, id.c_str(), ok)) {
     123          561 :         MSLane* lane = MSLane::dictionary(laneID);
     124          561 :         if (lane == nullptr) {
     125            0 :             throw InvalidArgument("The lane '" + laneID + "' to use within MSLaneSpeedTrigger '" + id + "' is not known.");
     126              :         }
     127          561 :         lanes.push_back(lane);
     128          507 :     }
     129          507 :     if (!ok) {
     130            0 :         throw InvalidArgument("The lanes to use within MSLaneSpeedTrigger '" + id + "' are not known.");
     131              :     }
     132          507 :     if (lanes.size() == 0) {
     133            0 :         throw InvalidArgument("No lane defined for MSLaneSpeedTrigger '" + id + "'.");
     134              :     }
     135              :     try {
     136          507 :         MSLaneSpeedTrigger* trigger = buildLaneSpeedTrigger(net, id, lanes, file);
     137          507 :         if (file == "") {
     138          339 :             trigger->registerParent(SUMO_TAG_VSS, myHandler);
     139              :         }
     140            0 :     } catch (ProcessError& e) {
     141            0 :         throw InvalidArgument(e.what());
     142            0 :     }
     143          507 : }
     144              : 
     145              : 
     146              : void
     147        11908 : NLTriggerBuilder::parseAndBuildChargingStation(MSNet& net, const SUMOSAXAttributes& attrs) {
     148        11908 :     bool ok = true;
     149              : 
     150              :     // get the id, throw if not given or empty...
     151        11908 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     152        11908 :     if (!ok) {
     153            0 :         throw ProcessError();
     154              :     }
     155              : 
     156        23816 :     MSLane* const lane = getLane(attrs, "chargingStation", id);
     157        11908 :     double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
     158        11908 :     double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
     159        11908 :     const double chargingPower = attrs.getOpt<double>(SUMO_ATTR_CHARGINGPOWER, id.c_str(), ok, 22000);
     160        11908 :     const double efficiency = attrs.getOpt<double>(SUMO_ATTR_EFFICIENCY, id.c_str(), ok, 0.95);
     161        11908 :     const bool chargeInTransit = attrs.getOpt<bool>(SUMO_ATTR_CHARGEINTRANSIT, id.c_str(), ok, 0);
     162        11908 :     const SUMOTime chargeDelay = attrs.getOptSUMOTimeReporting(SUMO_ATTR_CHARGEDELAY, id.c_str(), ok, 0);
     163        23824 :     const std::string chargeType = attrs.getOpt<std::string>(SUMO_ATTR_CHARGETYPE, id.c_str(), ok, "normal");
     164        11908 :     const SUMOTime waitingTime = attrs.getOptSUMOTimeReporting(SUMO_ATTR_WAITINGTIME, id.c_str(), ok, 900);
     165        11908 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
     166        11916 :     const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
     167        23816 :     MSParkingArea* parkingArea = getParkingArea(attrs, "parkingArea", id);
     168              : 
     169              :     // check charge type
     170        11908 :     if ((chargeType != "normal") && (chargeType != "battery-exchange") && (chargeType != "fuel")) {
     171           14 :         throw InvalidArgument("The chargeType to use within MSLaneSpeedTrigger '" + id + "' is invalid.");
     172              :     }
     173              : 
     174        11901 :     if (!ok || (myHandler->checkStopPos(frompos, topos, lane->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
     175            2 :         throw InvalidArgument("Invalid position for charging station '" + id + "'.");
     176              :     }
     177              : 
     178        35708 :     buildChargingStation(net, id, lane, frompos, topos, name, chargingPower, efficiency, chargeInTransit, chargeDelay, chargeType, waitingTime, parkingArea);
     179        11900 : }
     180              : 
     181              : 
     182              : void
     183           54 : NLTriggerBuilder::parseAndBuildOverheadWireSegment(MSNet& net, const SUMOSAXAttributes& attrs) {
     184           54 :     bool ok = true;
     185              : 
     186              :     // get the id, throw if not given or empty...
     187           54 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
     188           54 :     if (!ok) {
     189            0 :         throw ProcessError();
     190              :     }
     191              : 
     192              :     /* The following call may either throw InvalidArgument exeption or return NULL:
     193              :         NULL is returned in case when the overhead wire segment should be built over an already
     194              :         ignored internal lane of an intersection, the exeption is thrown in case that
     195              :         the overhead wire segment references a non-existent lane. */
     196           54 :     MSLane* const lane = getLane(attrs, "overheadWireSegment", id);
     197           54 :     if (lane == nullptr) {
     198            0 :         WRITE_MESSAGEF(TL("The overheadWireSegment '%' was not created as it is attached to internal lane. It will be build automatically."), id);
     199            0 :         return;
     200              :     }
     201              : 
     202           54 :     if (lane->isInternal()) {
     203            0 :         WRITE_MESSAGEF(TL("The overheadWireSegment '%' not built as it is attached to internal lane. It will be build automatically."), id);
     204            0 :         return;
     205              :     }
     206              : 
     207           54 :     double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
     208           54 :     double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
     209           54 :     const bool voltageSource = attrs.getOpt<bool>(SUMO_ATTR_VOLTAGESOURCE, id.c_str(), ok, false);
     210           54 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
     211              : 
     212           54 :     if (!ok || myHandler->checkStopPos(frompos, topos, lane->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID) {
     213            0 :         frompos = 0;
     214            0 :         topos = lane->getLength();
     215            0 :         WRITE_MESSAGEF(TL("The overheadWireSegment '%' has wrong position. Automatically set from 0 to the length of the lane."), id);
     216              :         //throw InvalidArgument("Invalid position for overheadWireSegment'" + id + "'.");
     217              :     }
     218              : 
     219           54 :     buildOverheadWireSegment(net, id, lane, frompos, topos, voltageSource);
     220              : #ifndef HAVE_EIGEN
     221              :     if (MSGlobals::gOverheadWireSolver && !myHaveWarnedAboutEigen) {
     222              :         myHaveWarnedAboutEigen = true;
     223              :         WRITE_WARNING(TL("Overhead wire solver (Eigen) not compiled in, expect errors in overhead wire simulation"))
     224              :     }
     225              : #endif // !HAVE_EIGEN
     226              : }
     227              : 
     228              : void
     229            8 : NLTriggerBuilder::parseAndBuildOverheadWireSection(MSNet& net, const SUMOSAXAttributes& attrs) {
     230            8 :     bool ok = true;
     231            8 :     std::string substationId = attrs.get<std::string>(SUMO_ATTR_SUBSTATIONID, 0, ok);
     232            8 :     if (!ok) {
     233            0 :         throw ProcessError();
     234              :     }
     235              : 
     236            8 :     MSTractionSubstation* substation = MSNet::getInstance()->findTractionSubstation(substationId);
     237            8 :     if (substation == nullptr) {
     238            0 :         throw InvalidArgument("Traction substation '" + substationId + "' refereced by an OverheadWire Section is not known.");
     239            8 :     } else if (substation->isAnySectionPreviouslyDefined()) {
     240            0 :         throw InvalidArgument("Traction substation '" + substationId + "' refereced by an OverheadWire Section is probably referenced twice (a known limitation of the actual version of overhead wire simulation).");
     241              :     }
     242              : 
     243              :     // @todo This may be a relict of older approach to processing the attributes ...
     244            8 :     std::string segmentStrings = attrs.get<std::string>(SUMO_ATTR_OVERHEAD_WIRE_SEGMENTS, substationId.c_str(), ok);
     245            8 :     if (!ok) {
     246            0 :         throw InvalidArgument("Segments referenced by Traction substation '" + substationId + "' are not declared .");
     247              :     }
     248              : 
     249              :     // process forbidden internal lanes
     250            8 :     const std::vector<std::string>& forbiddenInnerLanesIDs = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_OVERHEAD_WIRE_FORBIDDEN, substationId.c_str(), ok);
     251              :     /// @todo for cycle abbreviation?
     252            8 :     for (const std::string& laneID : forbiddenInnerLanesIDs) {
     253            0 :         MSLane* lane = MSLane::dictionary(laneID);
     254            0 :         if (lane != nullptr) {
     255            0 :             substation->addForbiddenLane(lane);
     256              :         } else {
     257            0 :             throw InvalidArgument("Unknown lane '" + laneID + "' in Traction substation '" + substationId + "'.");
     258              :         }
     259              :     }
     260              : 
     261              :     // @todo Check this as well ...
     262              :     // Original version from 2018
     263              :     // std::vector<std::string> segmentIDs;
     264              :     // SUMOSAXAttributes::parseStringVector(segmentStrings, segmentIDs);
     265            8 :     const std::vector<std::string>& segmentIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_OVERHEAD_WIRE_SEGMENTS, substationId.c_str(), ok);
     266              :     std::vector<MSOverheadWire*> segments;
     267              : 
     268              :     // ----------------------------------------------
     269              :     // Add overhead wire segments over internal lanes
     270              :     // ----------------------------------------------
     271              : 
     272              :     // Adding internal overhead wire segments (segments on neighboring inner lanes if a connection between two regular lane with overhead wire segment exists)
     273           46 :     for (const std::string& segmentID : segmentIDs) {
     274              :         const MSLane* connection = nullptr;
     275           38 :         MSOverheadWire* ovrhdSegment = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(segmentID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
     276              :         std::string neigboringOvrhdSegmentID;
     277              :         MSOverheadWire* neigboringOvrhdSegment;
     278              :         MSTractionSubstation* neigboringOvrhdSegmentTractionSubstation;
     279           38 :         if (ovrhdSegment == nullptr) {
     280            0 :             throw InvalidArgument("The OverheadWireSegment with id='" + segmentID + "' referenced by OverheadWireSegment for substation '" + substationId + "' was not defined.");
     281              :         }
     282              : 
     283              :         MSTractionSubstation* ts = ovrhdSegment->getTractionSubstation();
     284           38 :         if (!(ts == substation || ts == nullptr)) {
     285              :             std::string tsName = ts->getID();
     286            0 :             throw InvalidArgument("The OverheadWireSegment '" + segmentID + "' referenced by OverheadWireSegment for substation '" + substationId + "' is already assigned to substation '" + tsName + "'.");
     287              :         }
     288              :         ovrhdSegment->setTractionSubstation(substation);
     289              : 
     290           38 :         const MSLane* lane = &(ovrhdSegment->getLane());
     291              : 
     292              :         /* in version before SUMO 1.0.1 the function getOutgoingLanes() returning MSLane* exists,
     293              :         in new version of SUMO the funciton getOutgoingViaLanes() returning MSLane* and MSEdge* pair exists */
     294           38 :         const std::vector<std::pair<const MSLane*, const MSEdge*> > outgoingLanesAndEdges = lane->getOutgoingViaLanes();
     295              :         std::vector<const MSLane*> neigboringInnerLanes;
     296           38 :         neigboringInnerLanes.reserve(outgoingLanesAndEdges.size());
     297           89 :         for (size_t it = 0; it < outgoingLanesAndEdges.size(); ++it) {
     298           51 :             neigboringInnerLanes.push_back(outgoingLanesAndEdges[it].first);
     299              :         }
     300              : 
     301              :         // Check if an outgoing lane has an overhead wire segment. If not, do nothing, otherwise find connnecting internal lanes and
     302              :         // add overhead wire segments over all detected internal lanes
     303           89 :         for (std::vector<const MSLane*>::iterator it = neigboringInnerLanes.begin(); it != neigboringInnerLanes.end(); ++it) {
     304              :             // If the overhead wire segment is over the outgoing (not internal) lane
     305          102 :             neigboringOvrhdSegmentID = MSNet::getInstance()->getStoppingPlaceID(*it, NUMERICAL_EPS, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
     306           51 :             if (neigboringOvrhdSegmentID != "") {
     307           25 :                 neigboringOvrhdSegment = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(neigboringOvrhdSegmentID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
     308              :                 neigboringOvrhdSegmentTractionSubstation = neigboringOvrhdSegment->getTractionSubstation();
     309              :             } else {
     310              :                 neigboringOvrhdSegment = nullptr;
     311              :                 neigboringOvrhdSegmentTractionSubstation = nullptr;
     312              :             }
     313              : 
     314           51 :             if (neigboringOvrhdSegmentTractionSubstation == substation && !(*it)->isInternal()) {
     315            2 :                 connection = lane->getInternalFollowingLane(*it);
     316            2 :                 if (connection != nullptr) {
     317              :                     //is connection forbidden?
     318            2 :                     if (!(substation->isForbidden(connection) || substation->isForbidden(lane->getInternalFollowingLane(connection)) || substation->isForbidden(connection->getInternalFollowingLane(*it)))) {
     319            2 :                         buildInnerOverheadWireSegments(net, connection, lane->getInternalFollowingLane(connection), connection->getInternalFollowingLane(*it));
     320              :                     }
     321              :                 }
     322              :             }
     323              :         }
     324              : 
     325              :         // Check if an incoming lane has an overhead wire segment. If not, do nothing, otherwise find connnecting internal lanes and
     326              :         // add overhead wire segments over all detected internal lanes
     327           38 :         neigboringInnerLanes = lane->getNormalIncomingLanes();
     328          111 :         for (std::vector<const MSLane*>::iterator it = neigboringInnerLanes.begin(); it != neigboringInnerLanes.end(); ++it) {
     329              :             // If the overhead wire segment is over the incoming (not internal) lane
     330          146 :             neigboringOvrhdSegmentID = MSNet::getInstance()->getStoppingPlaceID(*it, (*it)->getLength() - NUMERICAL_EPS, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
     331           73 :             if (neigboringOvrhdSegmentID != "") {
     332           19 :                 neigboringOvrhdSegment = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(neigboringOvrhdSegmentID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
     333              :                 neigboringOvrhdSegmentTractionSubstation = neigboringOvrhdSegment->getTractionSubstation();
     334              :             } else {
     335              :                 neigboringOvrhdSegment = nullptr;
     336              :                 neigboringOvrhdSegmentTractionSubstation = nullptr;
     337              :             }
     338              : 
     339           73 :             if (neigboringOvrhdSegmentTractionSubstation == substation && !(*it)->isInternal()) {
     340           17 :                 connection = (*it)->getInternalFollowingLane(lane);
     341           17 :                 if (connection != nullptr) {
     342              :                     //is connection forbidden?
     343            2 :                     if (!(substation->isForbidden(connection) || substation->isForbidden((*it)->getInternalFollowingLane(connection)) || substation->isForbidden(connection->getInternalFollowingLane(lane)))) {
     344            2 :                         buildInnerOverheadWireSegments(net, connection, (*it)->getInternalFollowingLane(connection), connection->getInternalFollowingLane(lane));
     345              :                     }
     346              :                 }
     347              :             }
     348              :         }
     349           38 :     }
     350              : 
     351              : 
     352              :     // ----- *** adding segments into the electric circuit*** -----
     353              : 
     354              :     // setting nullptr for substation (a fragment from old version of adding segments into the circuit)
     355           46 :     for (const std::string& segmentID : segmentIDs) {
     356           38 :         MSOverheadWire* ovrhdSegment = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(segmentID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
     357              :         ovrhdSegment->setTractionSubstation(nullptr);
     358              :     }
     359              : 
     360           46 :     for (const std::string& segmentID : segmentIDs) {
     361           38 :         if (segmentID == "") {
     362            0 :             continue;
     363              :         }
     364           38 :         MSOverheadWire* ovrhdSegment = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(segmentID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
     365           38 :         substation->addOverheadWireSegmentToCircuit(ovrhdSegment);
     366           38 :         segments.push_back(ovrhdSegment);
     367              :     }
     368              : 
     369              :     // adding overhead wire clamp
     370           16 :     std::string clampsString = attrs.getOpt<std::string>(SUMO_ATTR_OVERHEAD_WIRE_CLAMPS, nullptr, ok, "");
     371            8 :     if (clampsString != "" && MSGlobals::gOverheadWireSolver) {
     372              : #ifdef HAVE_EIGEN
     373            5 :         const std::vector<std::string>& clampIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_OVERHEAD_WIRE_CLAMPS, nullptr, ok);
     374           16 :         for (const std::string& clampID : clampIDs) {
     375           11 :             MSTractionSubstation::OverheadWireClamp* clamp = substation->findClamp(clampID);
     376           11 :             if (clamp != nullptr) {
     377           11 :                 if (clamp->start->getTractionSubstation() == substation && clamp->end->getTractionSubstation() == substation) {
     378           11 :                     substation->addOverheadWireClampToCircuit(clamp->id, clamp->start, clamp->end);
     379           11 :                     buildOverheadWireClamp(net, clamp->id, const_cast<MSLane*>(&clamp->start->getLane()), const_cast<MSLane*>(&clamp->end->getLane()));
     380           11 :                     clamp->usage = true;
     381              :                 } else {
     382            0 :                     if (clamp->start->getTractionSubstation() != substation) {
     383            0 :                         WRITE_WARNINGF(TL("A connecting overhead wire start segment '%' defined for overhead wire clamp '%' is not assigned to the traction substation '%'."), clamp->start->getID(), clampID, substationId);
     384              :                     } else {
     385            0 :                         WRITE_WARNINGF(TL("A connecting overhead wire end segment '%' defined for overhead wire clamp '%' is not assigned to the traction substation '%'."), clamp->end->getID(), clampID, substationId);
     386              :                     }
     387              :                 }
     388              :             } else {
     389            0 :                 WRITE_WARNINGF(TL("The overhead wire clamp '%' defined in an overhead wire section was not assigned to the substation '%'. Please define proper <overheadWireClamp .../> in additional files before defining overhead wire section."), clampID, substationId);
     390              :             }
     391              :         }
     392              : #else
     393              :         WRITE_WARNING(TL("Overhead circuit solver requested, but solver support (Eigen) not compiled in."));
     394              : #endif
     395            5 :     }
     396              : 
     397            8 :     if (segments.size() == 0) {
     398            0 :         throw InvalidArgument("No segments found for overHeadWireSection '" + substationId + "'.");
     399            8 :     } else if (MSGlobals::gOverheadWireSolver) {
     400              : #ifdef HAVE_EIGEN
     401              :         // check that the electric circuit makes sense
     402           24 :         segments[0]->getCircuit()->checkCircuit(substationId);
     403              : #else
     404              :         WRITE_WARNING(TL("Cannot check circuit, overhead circuit solver support (Eigen) not compiled in."));
     405              : #endif
     406              :     }
     407           16 : }
     408              : 
     409              : void
     410            8 : NLTriggerBuilder::parseAndBuildTractionSubstation(MSNet& net, const SUMOSAXAttributes& attrs) {
     411            8 :     bool ok = true;
     412              : 
     413              :     // get the id, throw if not given or empty...
     414            8 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
     415            8 :     if (!ok) {
     416            0 :         throw ProcessError();
     417              :     }
     418              : 
     419              :     // RICE_TODO Limits are fixed, change them to some predefined constants ...
     420            8 :     const double voltage = attrs.getOpt<double>(SUMO_ATTR_VOLTAGE, id.c_str(), ok, 600);
     421            8 :     const double currentLimit = attrs.getOpt<double>(SUMO_ATTR_CURRENTLIMIT, id.c_str(), ok, 400);
     422           16 :     buildTractionSubstation(net, id, voltage, currentLimit);
     423            8 : }
     424              : 
     425              : void
     426           11 : NLTriggerBuilder::parseAndBuildOverheadWireClamp(MSNet& /*net*/, const SUMOSAXAttributes& attrs) {
     427           11 :     if (MSGlobals::gOverheadWireSolver) {
     428              : #ifdef HAVE_EIGEN
     429           11 :         bool ok = true;
     430           11 :         std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
     431           11 :         if (!ok) {
     432            0 :             throw ProcessError();
     433              :         }
     434              : 
     435           11 :         std::string substationId = attrs.get<std::string>(SUMO_ATTR_SUBSTATIONID, 0, ok);
     436           11 :         if (!ok) {
     437            0 :             throw ProcessError();
     438              :         }
     439           11 :         MSTractionSubstation* substation = MSNet::getInstance()->findTractionSubstation(substationId);
     440           11 :         if (substation == nullptr) {
     441            0 :             throw InvalidArgument("Traction substation '" + substationId + "' using within an overheadWireClamp '" + id + "' is not known.");
     442              :         }
     443              : 
     444           11 :         std::string overhead_fromItsStart = attrs.get<std::string>(SUMO_ATTR_OVERHEAD_WIRE_CLAMP_START, 0, ok);
     445           11 :         if (!ok) {
     446            0 :             throw ProcessError();
     447              :         }
     448           11 :         MSOverheadWire* ovrhdSegment_fromItsStart = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(overhead_fromItsStart, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
     449           11 :         if (ovrhdSegment_fromItsStart == nullptr) {
     450            0 :             throw InvalidArgument("The overheadWireSegment '" + overhead_fromItsStart + "' to use within overheadWireClamp '" + id + "' is not known.");
     451              :         }
     452              :         /*if (ovrhdSegment_fromItsStart->getTractionSubstation() != substation) {
     453              :             throw InvalidArgument("The overheadWireSegment '" + overhead_fromItsStart + "' to use within overheadWireClamp is assign to a different overhead wire section or substation.");
     454              :         }
     455              :         */
     456           11 :         std::string overhead_fromItsEnd = attrs.get<std::string>(SUMO_ATTR_OVERHEAD_WIRE_CLAMP_END, 0, ok);
     457           11 :         if (!ok) {
     458            0 :             throw ProcessError();
     459              :         }
     460           11 :         MSOverheadWire* ovrhdSegment_fromItsEnd = dynamic_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(overhead_fromItsEnd, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
     461           11 :         if (ovrhdSegment_fromItsEnd == nullptr) {
     462            0 :             throw InvalidArgument("The overheadWireSegment '" + overhead_fromItsEnd + "' to use within overheadWireClamp '" + id + "' is not known.");
     463              :         }
     464              :         /*
     465              :         if (ovrhdSegment_fromItsEnd->getTractionSubstation() != substation) {
     466              :             throw InvalidArgument("The overheadWireSegment '" + overhead_fromItsEnd + "' to use within overheadWireClamp is assign to a different overhead wire section or substation.");
     467              :         }
     468              :         */
     469           22 :         if (substation->findClamp(id) == nullptr) {
     470           11 :             substation->addClamp(id, ovrhdSegment_fromItsStart, ovrhdSegment_fromItsEnd);
     471              :         } else {
     472            0 :             WRITE_ERROR("The overhead wire clamp '" + id + "' is probably declared twice.")
     473              :         }
     474              : #else
     475              :         UNUSED_PARAMETER(attrs);
     476              :         WRITE_WARNING(TL("Not building overhead wire clamps, overhead wire solver support (Eigen) not compiled in."));
     477              : #endif
     478              :     } else {
     479            0 :         WRITE_WARNING(TL("Ignoring overhead wire clamps, they make no sense when overhead wire circuit solver is off."));
     480              :     }
     481           11 : }
     482              : 
     483              : 
     484              : void
     485        39247 : NLTriggerBuilder::parseAndBuildStoppingPlace(MSNet& net, const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
     486        39247 :     bool ok = true;
     487              :     // get the id, throw if not given or empty...
     488        39247 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     489        39247 :     if (!ok) {
     490            0 :         throw ProcessError();
     491              :     }
     492              : 
     493              :     //get the name, leave blank if not given
     494        78505 :     const std::string ptStopName = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
     495              : 
     496              :     //get the color, use default if not given
     497              :     // default color, copy from GUIVisualizationStoppingPlaceSettings::busStopColor / containerStopColor
     498        39247 :     RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok, RGBColor::INVISIBLE);
     499              : 
     500        78494 :     MSLane* lane = getLane(attrs, toString(element), id);
     501              :     // get the positions
     502        39247 :     double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0.);
     503        39247 :     double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
     504        39247 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
     505        39247 :     if (!ok || (myHandler->checkStopPos(frompos, topos, lane->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
     506            6 :         throw InvalidArgument("Invalid position for " + toString(element) + " '" + id + "'.");
     507              :     }
     508        39255 :     const std::vector<std::string>& lines = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_LINES, id.c_str(), ok);
     509              :     int defaultCapacity;
     510              :     SumoXMLAttr capacityAttr;
     511        39244 :     if (element != SUMO_TAG_CONTAINER_STOP) {
     512        29025 :         defaultCapacity = MAX2(MSStoppingPlace::getTransportablesAbreast(topos - frompos, element) * 3, 6);
     513              :         capacityAttr = SUMO_ATTR_PERSON_CAPACITY;
     514              :     } else {
     515        10219 :         defaultCapacity = MSStoppingPlace::getTransportablesAbreast(topos - frompos, element);
     516              :         capacityAttr = SUMO_ATTR_CONTAINER_CAPACITY;
     517              :     }
     518        39244 :     const int transportableCapacity = attrs.getOpt<int>(capacityAttr, id.c_str(), ok, defaultCapacity);
     519        39244 :     const double parkingLength = attrs.getOpt<double>(SUMO_ATTR_PARKING_LENGTH, id.c_str(), ok, 0);
     520              :     // build the bus stop
     521       156984 :     buildStoppingPlace(net, id, lines, lane, frompos, topos, element, ptStopName, transportableCapacity, parkingLength, color);
     522        78480 : }
     523              : 
     524              : 
     525              : void
     526         2276 : NLTriggerBuilder::addAccess(MSNet& /* net */, const SUMOSAXAttributes& attrs) {
     527         2276 :     if (myCurrentStop == nullptr) {
     528           30 :         throw InvalidArgument("Could not add access outside a stopping place.");
     529              :     }
     530              :     // get the lane
     531         4522 :     MSLane* lane = getLane(attrs, "access", myCurrentStop->getID());
     532         2261 :     if (!lane->allowsVehicleClass(SVC_PEDESTRIAN)) {
     533            0 :         WRITE_WARNINGF(TL("Ignoring invalid access from non-pedestrian lane '%' in busStop '%'."), lane->getID(), myCurrentStop->getID());
     534            0 :         return;
     535              :     }
     536              :     // get the positions
     537         2261 :     bool ok = true;
     538         2261 :     const std::string accessPos = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, "access", ok);
     539         2261 :     const bool random = accessPos == "random";
     540              :     MSStoppingPlace::AccessExit exit = MSStoppingPlace::AccessExit::PLATFORM;
     541         2261 :     if (accessPos == "doors") {
     542              :         exit = MSStoppingPlace::AccessExit::DOORS;
     543         2229 :     } else if (accessPos == "carriage") {
     544              :         exit = MSStoppingPlace::AccessExit::CARRIAGE;
     545              :     }
     546         2261 :     double startPos = random || exit != MSStoppingPlace::AccessExit::PLATFORM ? 0. : attrs.getOpt<double>(SUMO_ATTR_POSITION, "access", ok, 0);
     547         2261 :     double endPos = random || exit != MSStoppingPlace::AccessExit::PLATFORM ? lane->getLength() : startPos;
     548         2261 :     const double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "access", ok, -1);
     549         2261 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, "access", ok, false);
     550         2261 :     if (!ok || (myHandler->checkStopPos(startPos, endPos, lane->getLength(), 0, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
     551            0 :         throw InvalidArgument("Invalid position " + attrs.getString(SUMO_ATTR_POSITION) + " for access on lane '" + lane->getID() + "' in stop '" + myCurrentStop->getID() + "'.");
     552              :     }
     553              :     // add bus stop access
     554         2261 :     if (!myCurrentStop->addAccess(lane, startPos, endPos, length, exit)) {
     555           14 :         throw InvalidArgument("Duplicate access on lane '" + lane->getID() + "' for stop '" + myCurrentStop->getID() + "'");
     556              :     }
     557              : }
     558              : 
     559              : 
     560              : void
     561        13516 : NLTriggerBuilder::parseAndBeginParkingArea(MSNet& net, const SUMOSAXAttributes& attrs) {
     562        13516 :     bool ok = true;
     563              :     // get the id, throw if not given or empty...
     564        13516 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     565        13516 :     if (!ok) {
     566            0 :         throw ProcessError();
     567              :     }
     568              :     // get the lane
     569        27032 :     MSLane* lane = getLane(attrs, "parkingArea", id);
     570              :     // get the positions
     571        13516 :     double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
     572        13516 :     double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
     573        13516 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
     574        13516 :     unsigned int capacity = attrs.getOpt<int>(SUMO_ATTR_ROADSIDE_CAPACITY, id.c_str(), ok, 0);
     575        13516 :     myParkingAreaCapacitySet = attrs.hasAttribute(SUMO_ATTR_ROADSIDE_CAPACITY);
     576        13516 :     bool onRoad = attrs.getOpt<bool>(SUMO_ATTR_ONROAD, id.c_str(), ok, false);
     577        13516 :     double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, id.c_str(), ok, 0);
     578        13516 :     double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, id.c_str(), ok, 0);
     579        13516 :     double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, id.c_str(), ok, 0);
     580        27033 :     const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok);
     581        27033 :     const std::string departPos = attrs.getOpt<std::string>(SUMO_ATTR_DEPARTPOS, id.c_str(), ok);
     582        13516 :     bool lefthand = attrs.getOpt<bool>(SUMO_ATTR_LEFTHAND, id.c_str(), ok, false);
     583        13517 :     const std::vector<std::string>& acceptedBadges = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_ACCEPTED_BADGES, id.c_str(), ok);
     584              : 
     585        13516 :     if (!ok || (myHandler->checkStopPos(frompos, topos, lane->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
     586            2 :         throw InvalidArgument("Invalid position for parking area '" + id + "'.");
     587              :     }
     588        13515 :     const std::vector<std::string>& lines = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_LINES, id.c_str(), ok);
     589              :     // build the parking area
     590        13515 :     beginParkingArea(net, id, lines, acceptedBadges, lane, frompos, topos, capacity, width, length, angle, name, onRoad, departPos, lefthand);
     591        27031 : }
     592              : 
     593              : 
     594              : 
     595              : void
     596          670 : NLTriggerBuilder::parseAndAddLotEntry(const SUMOSAXAttributes& attrs) {
     597          670 :     bool ok = true;
     598              :     // Check for open parking area
     599          670 :     if (myParkingArea == nullptr) {
     600            0 :         throw ProcessError();
     601              :     }
     602              :     // get the positions
     603          670 :     double x = attrs.get<double>(SUMO_ATTR_X, "", ok);
     604          670 :     if (!ok) {
     605            0 :         throw InvalidArgument("Invalid x position for lot entry.");
     606              :     }
     607          670 :     double y = attrs.get<double>(SUMO_ATTR_Y, "", ok);
     608          670 :     if (!ok) {
     609            0 :         throw InvalidArgument("Invalid y position for lot entry.");
     610              :     }
     611          670 :     double z = attrs.getOpt<double>(SUMO_ATTR_Z, "", ok, 0.);
     612          670 :     double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, "", ok, myParkingArea->getWidth());
     613          670 :     double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "", ok, myParkingArea->getLength());
     614          670 :     double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, "", ok, myParkingArea->getAngle());
     615          670 :     double slope = attrs.getOpt<double>(SUMO_ATTR_SLOPE, "", ok, 0.);
     616              :     // add the lot entry
     617          670 :     addLotEntry(x, y, z, width, length, angle, slope);
     618          670 : }
     619              : 
     620              : 
     621              : void
     622          953 : NLTriggerBuilder::parseAndBuildCalibrator(MSNet& net, const SUMOSAXAttributes& attrs,
     623              :         const std::string& base) {
     624          953 :     bool ok = true;
     625              :     // get the id, throw if not given or empty...
     626          953 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     627          953 :     if (!ok) {
     628            0 :         throw ProcessError();
     629              :     }
     630              :     MSLane* lane = nullptr;
     631              :     MSEdge* edge = nullptr;
     632              :     MSJunction* node = nullptr;
     633          953 :     if (attrs.hasAttribute(SUMO_ATTR_NODE)) {
     634           14 :         if (attrs.hasAttribute(SUMO_ATTR_LANE) || attrs.hasAttribute(SUMO_ATTR_EDGE)) {
     635            0 :             throw InvalidArgument("The node calibrator '" + id + "' cannot define an edge or lane as well.");
     636              :         }
     637           14 :         const std::string nodeID = attrs.get<std::string>(SUMO_ATTR_NODE, id.c_str(), ok);
     638              :         node = net.getJunctionControl().get(nodeID);
     639           14 :         if (node == nullptr) {
     640            0 :             throw InvalidArgument("The node " + nodeID + " to use within the calibrator '" + id + "' is not known.");
     641              :         }
     642              :     } else {
     643          939 :         if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
     644          479 :             const std::string edgeID = attrs.get<std::string>(SUMO_ATTR_EDGE, id.c_str(), ok);
     645          479 :             edge = MSEdge::dictionary(edgeID);
     646          479 :             if (edge == nullptr) {
     647            0 :                 throw InvalidArgument("The edge " + edgeID + " to use within the calibrator '" + id + "' is not known.");
     648              :             }
     649          479 :             if (attrs.hasAttribute(SUMO_ATTR_LANE)) {
     650            0 :                 lane = getLane(attrs, "calibrator", id);
     651            0 :                 if (&lane->getEdge() != edge) {
     652            0 :                     throw InvalidArgument("The edge " + edgeID + " to use within the calibrator '" + id
     653            0 :                                           + "' does not match the calibrator lane '" + lane->getID() + ".");
     654              :                 }
     655              :             }
     656              :         } else {
     657          920 :             lane = getLane(attrs, "calibrator", id);
     658              :             edge = &lane->getEdge();
     659              :         }
     660              :     }
     661          953 :     const double pos = node != nullptr ? 0 : getPosition(attrs, lane, "calibrator", id, edge);
     662          952 :     const SUMOTime period = attrs.getOptPeriod(id.c_str(), ok, DELTA_T); // !!! no error handling
     663          953 :     const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
     664          952 :     const std::string file = getFileName(attrs, base, true);
     665          952 :     const std::string outfile = attrs.getOpt<std::string>(SUMO_ATTR_OUTPUT, id.c_str(), ok, "");
     666          952 :     const std::string routeProbe = attrs.getOpt<std::string>(SUMO_ATTR_ROUTEPROBE, id.c_str(), ok, "");
     667              :     // differing defaults for backward compatibility, values are dimensionless
     668         1820 :     const double invalidJamThreshold = attrs.getOpt<double>(SUMO_ATTR_JAM_DIST_THRESHOLD, id.c_str(), ok, MSGlobals::gUseMesoSim ? 0.8 : 0.5);
     669          952 :     const bool local = attrs.getOpt<bool>(SUMO_ATTR_LOCAL, id.c_str(), ok, false);
     670              :     MSRouteProbe* probe = nullptr;
     671          952 :     if (routeProbe != "") {
     672           72 :         probe = dynamic_cast<MSRouteProbe*>(net.getDetectorControl().getTypedDetectors(SUMO_TAG_ROUTEPROBE).get(routeProbe));
     673           36 :         if (probe == nullptr) {
     674            0 :             throw InvalidArgument("The routeProbe '" + routeProbe + "' to use within the calibrator '" + id + "' is not known.");
     675              :         }
     676              :     }
     677          952 :     if (MSGlobals::gUseMesoSim) {
     678           84 :         if (lane != nullptr && edge->getLanes().size() > 1) {
     679           27 :             WRITE_WARNING("Meso calibrator '" + id
     680              :                           + "' defined for lane '" + lane->getID()
     681              :                           + "' will collect data for all lanes of edge '" + edge->getID() + "'.");
     682              :         }
     683           84 :         METriggeredCalibrator* trigger = buildMECalibrator(id, edge, pos, file, outfile, period, probe, invalidJamThreshold, vTypes);
     684           84 :         if (file == "") {
     685           72 :             trigger->registerParent(SUMO_TAG_CALIBRATOR, myHandler);
     686              :         }
     687              :     } else {
     688          868 :         MSCalibrator* trigger = buildCalibrator(id, edge, lane, node, pos, file, outfile, period, probe, invalidJamThreshold, vTypes, local);
     689          868 :         if (file == "") {
     690          838 :             trigger->registerParent(SUMO_TAG_CALIBRATOR, myHandler);
     691              :         }
     692              :     }
     693          952 : }
     694              : 
     695              : 
     696              : void
     697         3425 : NLTriggerBuilder::parseAndBuildRerouter(MSNet& net, const SUMOSAXAttributes& attrs) {
     698         3425 :     bool ok = true;
     699              :     // get the id, throw if not given or empty...
     700         3425 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     701         3425 :     if (!ok) {
     702            0 :         throw ProcessError();
     703              :     }
     704              :     if (MSTriggeredRerouter::getInstances().count(id) > 0) {
     705           14 :         throw InvalidArgument("Could not build rerouter '" + id + "'; probably declared twice.");
     706              :     }
     707              :     MSEdgeVector edges;
     708         7970 :     for (const std::string& edgeID : attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, id.c_str(), ok)) {
     709         4552 :         MSEdge* edge = MSEdge::dictionary(edgeID);
     710         4552 :         if (edge == nullptr) {
     711            0 :             throw InvalidArgument("The edge '" + edgeID + "' to use within rerouter '" + id + "' is not known.");
     712              :         }
     713         4552 :         edges.push_back(edge);
     714         3418 :     }
     715         3418 :     if (!ok) {
     716            0 :         throw InvalidArgument("The edge to use within rerouter '" + id + "' is not known.");
     717              :     }
     718         3418 :     if (edges.size() == 0) {
     719            0 :         throw InvalidArgument("No edges found for rerouter '" + id + "'.");
     720              :     }
     721         3418 :     const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, id.c_str(), ok, 1);
     722         3418 :     const bool off = attrs.getOpt<bool>(SUMO_ATTR_OFF, id.c_str(), ok, false);
     723         3418 :     const bool optional = attrs.getOpt<bool>(SUMO_ATTR_OPTIONAL, id.c_str(), ok, false);
     724         3418 :     const SUMOTime timeThreshold = TIME2STEPS(attrs.getOpt<double>(SUMO_ATTR_HALTING_TIME_THRESHOLD, id.c_str(), ok, 0));
     725         3418 :     const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
     726         6836 :     const std::string pos = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, id.c_str(), ok, "");
     727         3418 :     const double radius = attrs.getOpt<double>(SUMO_ATTR_RADIUS, id.c_str(), ok, std::numeric_limits<double>::max());
     728         3418 :     Position p = Position::INVALID;
     729         3418 :     if (pos != "") {
     730          699 :         const std::vector<std::string> posSplit = StringTokenizer(pos, ",").getVector();
     731          233 :         if (posSplit.size() == 1) {
     732            4 :             p = edges.front()->getLanes()[0]->geometryPositionAtOffset(StringUtils::toDouble(posSplit[0]));
     733          231 :         } else if (posSplit.size() == 2) {
     734          231 :             p = Position(StringUtils::toDouble(posSplit[0]), StringUtils::toDouble(posSplit[1]));
     735            0 :         } else if (posSplit.size() == 3) {
     736            0 :             p = Position(StringUtils::toDouble(posSplit[0]), StringUtils::toDouble(posSplit[1]), StringUtils::toDouble(posSplit[2]));
     737              :         } else {
     738            0 :             throw InvalidArgument("Invalid position for rerouter '" + id + "'.");
     739              :         }
     740          233 :     }
     741         3418 :     if (!ok) {
     742            0 :         throw InvalidArgument("Could not parse rerouter '" + id + "'.");
     743              :     }
     744         3418 :     MSTriggeredRerouter* trigger = buildRerouter(net, id, edges, prob, off, optional, timeThreshold, vTypes, p, radius);
     745              :     // read in the trigger description
     746         3418 :     trigger->registerParent(SUMO_TAG_REROUTER, myHandler);
     747         6836 : }
     748              : 
     749              : 
     750              : // -------------------------
     751              : 
     752              : 
     753              : MSLaneSpeedTrigger*
     754          407 : NLTriggerBuilder::buildLaneSpeedTrigger(MSNet& /*net*/, const std::string& id,
     755              :                                         const std::vector<MSLane*>& destLanes,
     756              :                                         const std::string& file) {
     757          407 :     return new MSLaneSpeedTrigger(id, destLanes, file);
     758              : }
     759              : 
     760              : 
     761              : METriggeredCalibrator*
     762           84 : NLTriggerBuilder::buildMECalibrator(const std::string& id,
     763              :                                     MSEdge* edge,
     764              :                                     double pos,
     765              :                                     const std::string& file,
     766              :                                     const std::string& outfile,
     767              :                                     const SUMOTime freq,
     768              :                                     MSRouteProbe* probe,
     769              :                                     const double invalidJamThreshold,
     770              :                                     const std::string& vTypes) {
     771              :     return new METriggeredCalibrator(id, edge, pos, file, outfile, freq,
     772           80 :                                      edge == nullptr ? 0. : MSGlobals::gMesoNet->getSegmentForEdge(*edge, pos)->getLength(),
     773          164 :                                      probe, invalidJamThreshold, vTypes);
     774              : }
     775              : 
     776              : 
     777              : MSCalibrator*
     778          868 : NLTriggerBuilder::buildCalibrator(const std::string& id,
     779              :                                   MSEdge* edge,
     780              :                                   MSLane* lane,
     781              :                                   MSJunction* node,
     782              :                                   double pos,
     783              :                                   const std::string& file,
     784              :                                   const std::string& outfile,
     785              :                                   const SUMOTime freq,
     786              :                                   const MSRouteProbe* probe,
     787              :                                   const double invalidJamThreshold,
     788              :                                   const std::string& vTypes,
     789              :                                   const bool local) {
     790              :     return new MSCalibrator(id, edge, lane, node, pos, file, outfile, freq,
     791              :                             edge == nullptr ? 0. : edge->getLength(),
     792         1726 :                             probe, invalidJamThreshold, vTypes, local, true);
     793              : }
     794              : 
     795              : 
     796              : MSTriggeredRerouter*
     797         2758 : NLTriggerBuilder::buildRerouter(MSNet&, const std::string& id,
     798              :                                 MSEdgeVector& edges, double prob, bool off, bool optional,
     799              :                                 SUMOTime timeThreshold, const std::string& vTypes, const Position& pos, const double radius) {
     800         2758 :     return new MSTriggeredRerouter(id, edges, prob, off, optional, timeThreshold, vTypes, pos, radius);
     801              : }
     802              : 
     803              : 
     804              : void
     805        37543 : NLTriggerBuilder::buildStoppingPlace(MSNet& net, std::string id, std::vector<std::string> lines, MSLane* lane,
     806              :                                      double frompos, double topos, const SumoXMLTag element, std::string ptStopName,
     807              :                                      int personCapacity, double parkingLength, RGBColor& color) {
     808        75086 :     myCurrentStop = new MSStoppingPlace(id, element, lines, *lane, frompos, topos, ptStopName, personCapacity, parkingLength, color);
     809        37543 :     if (!net.addStoppingPlace(element, myCurrentStop)) {
     810            5 :         delete myCurrentStop;
     811            5 :         myCurrentStop = nullptr;
     812           10 :         throw InvalidArgument("Could not build " + toString(element) + " '" + id + "'; probably declared twice.");
     813              :     }
     814        37538 : }
     815              : 
     816              : 
     817              : void
     818        12789 : NLTriggerBuilder::beginParkingArea(MSNet& net, const std::string& id,
     819              :                                    const std::vector<std::string>& lines,
     820              :                                    const std::vector<std::string>& badges,
     821              :                                    MSLane* lane, double frompos, double topos,
     822              :                                    unsigned int capacity,
     823              :                                    double width, double length, double angle, const std::string& name,
     824              :                                    bool onRoad,
     825              :                                    const std::string& departPos,
     826              :                                    bool lefthand) {
     827              :     // Close previous parking area if there are no lots inside
     828        12789 :     MSParkingArea* stop = new MSParkingArea(id, lines, badges, *lane, frompos, topos, capacity, width, length, angle, name, onRoad, departPos, lefthand);
     829        12789 :     if (!net.addStoppingPlace(SUMO_TAG_PARKING_AREA, stop)) {
     830            0 :         delete stop;
     831            0 :         throw InvalidArgument("Could not build parking area '" + id + "'; probably declared twice.");
     832              :     } else {
     833        12789 :         myParkingArea = stop;
     834              :     }
     835        12789 : }
     836              : 
     837              : 
     838              : void
     839          670 : NLTriggerBuilder::addLotEntry(double x, double y, double z,
     840              :                               double width, double length,
     841              :                               double angle, double slope) {
     842          670 :     if (myParkingArea != nullptr) {
     843          670 :         if (!myParkingArea->parkOnRoad()) {
     844          670 :             myParkingArea->addLotEntry(x, y, z, width, length, angle, slope);
     845          670 :             myParkingAreaCapacitySet = true;
     846              :         } else {
     847            0 :             throw InvalidArgument("Cannot not add lot entry to on-road parking area.");
     848              :         }
     849              :     } else {
     850            0 :         throw InvalidArgument("Could not add lot entry outside a parking area.");
     851              :     }
     852          670 : }
     853              : 
     854              : 
     855              : void
     856        12790 : NLTriggerBuilder::endParkingArea() {
     857        12790 :     if (myParkingArea != nullptr) {
     858        12789 :         myParkingArea = nullptr;
     859        12789 :         myParkingAreaCapacitySet = false;
     860              :     } else {
     861            2 :         throw InvalidArgument("Could not end a parking area that is not opened.");
     862              :     }
     863        12789 : }
     864              : 
     865              : 
     866              : void
     867        49183 : NLTriggerBuilder::endStoppingPlace() {
     868        49183 :     if (myCurrentStop != nullptr) {
     869        49167 :         myCurrentStop = nullptr;
     870              :     } else {
     871           32 :         throw InvalidArgument("Could not end a stopping place that is not opened.");
     872              :     }
     873        49167 : }
     874              : 
     875              : 
     876              : void
     877        11629 : NLTriggerBuilder::buildChargingStation(MSNet& net, const std::string& id, MSLane* lane, double frompos, double topos,
     878              :                                        const std::string& name, double chargingPower, double efficiency, bool chargeInTransit,
     879              :                                        SUMOTime chargeDelay, std::string chargeType, SUMOTime waitingTime, MSParkingArea* parkingArea) {
     880        11629 :     MSChargingStation* chargingStation = (parkingArea == nullptr) ? new MSChargingStation(id, *lane, frompos, topos, name, chargingPower, efficiency,
     881        11621 :                                          chargeInTransit, chargeDelay, chargeType, waitingTime) : new MSChargingStation(id, parkingArea, name, chargingPower, efficiency,
     882            8 :                                                  chargeInTransit, chargeDelay, chargeType, waitingTime);
     883        11629 :     if (!net.addStoppingPlace(SUMO_TAG_CHARGING_STATION, chargingStation)) {
     884            0 :         delete chargingStation;
     885            0 :         throw InvalidArgument("Could not build charging station '" + id + "'; probably declared twice.");
     886              :     }
     887        11629 :     myCurrentStop = chargingStation;
     888        11629 : }
     889              : 
     890              : 
     891              : void
     892           46 : NLTriggerBuilder::buildOverheadWireSegment(MSNet& net, const std::string& id, MSLane* lane, double frompos, double topos,
     893              :         bool voltageSource) {
     894           46 :     MSOverheadWire* overheadWireSegment = new MSOverheadWire(id, *lane, frompos, topos, voltageSource);
     895           46 :     if (!net.addStoppingPlace(SUMO_TAG_OVERHEAD_WIRE_SEGMENT, overheadWireSegment)) {
     896            0 :         delete overheadWireSegment;
     897            0 :         throw InvalidArgument("Could not build overheadWireSegment '" + id + "'; probably declared twice.");
     898              :     }
     899           46 : }
     900              : 
     901              : void
     902            4 : NLTriggerBuilder::buildInnerOverheadWireSegments(MSNet& net, const MSLane* connection, const MSLane* frontConnection, const MSLane* behindConnection) {
     903            4 :     if (frontConnection == NULL && behindConnection == NULL) {
     904            8 :         buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
     905            0 :     } else if (frontConnection != NULL && behindConnection == NULL) {
     906            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + frontConnection->getID(), const_cast<MSLane*>(frontConnection), 0, frontConnection->getLength(), false);
     907            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
     908            0 :     } else if (frontConnection == NULL && behindConnection != NULL) {
     909            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + behindConnection->getID(), const_cast<MSLane*>(behindConnection), 0, behindConnection->getLength(), false);
     910            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
     911            0 :     } else if (frontConnection != NULL && behindConnection != NULL) {
     912            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + frontConnection->getID(), const_cast<MSLane*>(frontConnection), 0, frontConnection->getLength(), false);
     913            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + behindConnection->getID(), const_cast<MSLane*>(behindConnection), 0, behindConnection->getLength(), false);
     914            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
     915              :     }
     916            4 : }
     917              : 
     918              : void
     919            8 : NLTriggerBuilder::buildTractionSubstation(MSNet& net, std::string id, double voltage, double currentLimit) {
     920            8 :     MSTractionSubstation* myTractionSubstation = new MSTractionSubstation(id, voltage, currentLimit);
     921            8 :     if (!net.addTractionSubstation(myTractionSubstation)) {
     922            0 :         delete myTractionSubstation;
     923            0 :         throw InvalidArgument("Could not build traction substation '" + id + "'; probably declared twice.");
     924              :     }
     925            8 : }
     926              : 
     927              : void
     928           10 : NLTriggerBuilder::buildOverheadWireClamp(MSNet& /*net*/, const std::string& /*id*/, MSLane* /*lane_start*/, MSLane* /*lane_end*/) {
     929           10 : }
     930              : 
     931              : std::string
     932         1459 : NLTriggerBuilder::getFileName(const SUMOSAXAttributes& attrs,
     933              :                               const std::string& base,
     934              :                               const bool allowEmpty) {
     935              :     // get the file name to read further definitions from
     936         1459 :     bool ok = true;
     937         1459 :     std::string file = attrs.getOpt<std::string>(SUMO_ATTR_FILE, nullptr, ok, "");
     938         1459 :     if (file == "") {
     939         1249 :         if (allowEmpty) {
     940         1249 :             return file;
     941              :         }
     942            0 :         throw InvalidArgument("No filename given.");
     943              :     }
     944              :     // check whether absolute or relative filenames are given
     945          210 :     if (!FileHelpers::isAbsolute(file)) {
     946          210 :         return FileHelpers::getConfigurationRelative(base, file);
     947              :     }
     948            0 :     return file;
     949              : }
     950              : 
     951              : 
     952              : MSLane*
     953        67446 : NLTriggerBuilder::getLane(const SUMOSAXAttributes& attrs,
     954              :                           const std::string& tt,
     955              :                           const std::string& tid) {
     956        67446 :     bool ok = true;
     957        67446 :     std::string objectid = attrs.get<std::string>(SUMO_ATTR_LANE, tid.c_str(), ok);
     958        67446 :     MSLane* lane = MSLane::dictionary(objectid);
     959        67446 :     if (lane == nullptr) {
     960              :         // Either a lane that is non-existent/broken, or a lane that is internal and has been ignored.
     961              :         // We assume that internal lane names start with ':'.
     962            0 :         if (objectid[0] == ':' && !MSGlobals::gUsingInternalLanes) {
     963              :             return nullptr;
     964              :         }
     965              :         // Throw the exception only in case that the lane really does not exist in the network file
     966              :         // or it is broken.
     967            0 :         throw InvalidArgument("The lane " + objectid + " to use within the " + tt + " '" + tid + "' is not known.");
     968              :     }
     969              :     return lane;
     970              : }
     971              : 
     972              : 
     973              : MSParkingArea*
     974        11908 : NLTriggerBuilder::getParkingArea(const SUMOSAXAttributes& attrs, const std::string& tt, const std::string& tid) {
     975        11908 :     bool ok = true;
     976        11908 :     std::string objectID = attrs.getOpt<std::string>(SUMO_ATTR_PARKING_AREA, tid.c_str(), ok);
     977        11908 :     if (!ok || objectID.size() == 0) {
     978              :         return nullptr;
     979              :     }
     980           11 :     MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_PARKING_AREA));
     981           11 :     if (pa == nullptr) {
     982              :         // Throw the exception only in case that the lane really does not exist in the network file
     983              :         // or it is broken.
     984            0 :         throw InvalidArgument("The parkingArea " + objectID + " to use within the " + tt + " '" + tid + "' is not known.");
     985              :     }
     986              :     return pa;
     987              : }
     988              : 
     989              : 
     990              : double
     991          939 : NLTriggerBuilder::getPosition(const SUMOSAXAttributes& attrs,
     992              :                               MSLane* lane,
     993              :                               const std::string& tt, const std::string& tid,
     994              :                               MSEdge* edge) {
     995              :     assert(lane != nullptr || edge != nullptr);
     996          939 :     const double length = lane != nullptr ? lane->getLength() : edge->getLength();
     997          939 :     bool ok = true;
     998          939 :     double pos = attrs.get<double>(SUMO_ATTR_POSITION, nullptr, ok);
     999          939 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, nullptr, ok, false);
    1000          939 :     if (!ok) {
    1001            0 :         throw InvalidArgument("Error on parsing a position information.");
    1002              :     }
    1003          939 :     if (pos < 0) {
    1004            2 :         pos = length + pos;
    1005              :     }
    1006          939 :     if (pos > length) {
    1007            1 :         if (friendlyPos) {
    1008            0 :             pos = length - (double) 0.1;
    1009              :         } else {
    1010            1 :             if (lane != nullptr) {
    1011            2 :                 throw InvalidArgument("The position of " + tt + " '" + tid + "' lies beyond the lane's '" + lane->getID() + "' length.");
    1012              :             } else {
    1013            0 :                 throw InvalidArgument("The position of " + tt + " '" + tid + "' lies beyond the edge's '" + edge->getID() + "' length.");
    1014              :             }
    1015              :         }
    1016              :     }
    1017          938 :     return pos;
    1018              : }
    1019              : 
    1020              : 
    1021              : void
    1022        13516 : NLTriggerBuilder::updateParkingAreaDefaultCapacity() {
    1023        13516 :     if (myParkingArea != nullptr && !myParkingAreaCapacitySet) {
    1024         9709 :         myParkingArea->setRoadsideCapacity(1);
    1025              :     }
    1026        13516 : }
    1027              : 
    1028              : 
    1029              : MSStoppingPlace*
    1030        64651 : NLTriggerBuilder::getCurrentStop() {
    1031        64651 :     return myParkingArea == nullptr ? myCurrentStop : myParkingArea;
    1032              : }
    1033              : 
    1034              : 
    1035              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1