LCOV - code coverage report
Current view: top level - src/netload - NLTriggerBuilder.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 383 481 79.6 %
Date: 2024-05-04 15:27:10 Functions: 35 36 97.2 %

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

Generated by: LCOV version 1.14