LCOV - code coverage report
Current view: top level - src/netload - NLTriggerBuilder.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 80.5 % 502 404
Test Date: 2024-11-20 15:55:46 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        42766 : NLTriggerBuilder::NLTriggerBuilder()
      61        42766 :     : myHandler(nullptr), myParkingArea(nullptr), myCurrentStop(nullptr) {}
      62              : 
      63              : 
      64        42766 : NLTriggerBuilder::~NLTriggerBuilder() {}
      65              : 
      66              : void
      67        42766 : NLTriggerBuilder::setHandler(NLHandler* handler) {
      68        42766 :     myHandler = handler;
      69        42766 : }
      70              : 
      71              : 
      72              : void
      73          482 : NLTriggerBuilder::buildVaporizer(const SUMOSAXAttributes& attrs) {
      74          482 :     WRITE_WARNING(TL("Vaporizers are deprecated. Use rerouters instead."));
      75          482 :     bool ok = true;
      76              :     // get the id, throw if not given or empty...
      77          482 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
      78          482 :     if (!ok) {
      79              :         return;
      80              :     }
      81          470 :     MSEdge* e = MSEdge::dictionary(id);
      82          470 :     if (e == nullptr) {
      83           18 :         WRITE_ERRORF(TL("Unknown edge ('%') referenced in a vaporizer."), id);
      84            6 :         return;
      85              :     }
      86          464 :     SUMOTime begin = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok);
      87          464 :     SUMOTime end = attrs.getSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok);
      88          464 :     if (!ok) {
      89              :         return;
      90              :     }
      91          428 :     if (begin < 0) {
      92           18 :         WRITE_ERRORF(TL("A vaporization begin time is negative (edge id='%')."), id);
      93            6 :         return;
      94              :     }
      95          422 :     if (begin >= end) {
      96           36 :         WRITE_ERRORF(TL("A vaporization ends before it starts (edge id='%')."), id);
      97           12 :         return;
      98              :     }
      99          820 :     if (end >= string2time(OptionsCont::getOptions().getString("begin"))) {
     100          410 :         Command* cb = new WrappingCommand< MSEdge >(e, &MSEdge::incVaporization);
     101          410 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(cb, begin);
     102          410 :         Command* ce = new WrappingCommand< MSEdge >(e, &MSEdge::decVaporization);
     103          410 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(ce, end);
     104              :     }
     105              : }
     106              : 
     107              : 
     108              : void
     109          477 : NLTriggerBuilder::parseAndBuildLaneSpeedTrigger(MSNet& net, const SUMOSAXAttributes& attrs,
     110              :         const std::string& base) {
     111              :     // get the id, throw if not given or empty...
     112          477 :     bool ok = true;
     113              :     // get the id, throw if not given or empty...
     114          477 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     115          477 :     if (!ok) {
     116              :         return;
     117              :     }
     118              :     // get the file name to read further definitions from
     119          477 :     std::string file = getFileName(attrs, base, true);
     120          477 :     std::string objectid = attrs.get<std::string>(SUMO_ATTR_LANES, id.c_str(), ok);
     121              :     std::vector<MSLane*> lanes;
     122         1008 :     for (const std::string& laneID : attrs.get<std::vector<std::string> >(SUMO_ATTR_LANES, id.c_str(), ok)) {
     123          531 :         MSLane* lane = MSLane::dictionary(laneID);
     124          531 :         if (lane == nullptr) {
     125            0 :             throw InvalidArgument("The lane '" + laneID + "' to use within MSLaneSpeedTrigger '" + id + "' is not known.");
     126              :         }
     127          531 :         lanes.push_back(lane);
     128          477 :     }
     129          477 :     if (!ok) {
     130            0 :         throw InvalidArgument("The lanes to use within MSLaneSpeedTrigger '" + id + "' are not known.");
     131              :     }
     132          477 :     if (lanes.size() == 0) {
     133            0 :         throw InvalidArgument("No lane defined for MSLaneSpeedTrigger '" + id + "'.");
     134              :     }
     135              :     try {
     136          477 :         MSLaneSpeedTrigger* trigger = buildLaneSpeedTrigger(net, id, lanes, file);
     137          477 :         if (file == "") {
     138          309 :             trigger->registerParent(SUMO_TAG_VSS, myHandler);
     139              :         }
     140            0 :     } catch (ProcessError& e) {
     141            0 :         throw InvalidArgument(e.what());
     142            0 :     }
     143          477 : }
     144              : 
     145              : 
     146              : void
     147        11686 : NLTriggerBuilder::parseAndBuildChargingStation(MSNet& net, const SUMOSAXAttributes& attrs) {
     148        11686 :     bool ok = true;
     149              : 
     150              :     // get the id, throw if not given or empty...
     151        11686 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     152        11686 :     if (!ok) {
     153            0 :         throw ProcessError();
     154              :     }
     155              : 
     156        23372 :     MSLane* const lane = getLane(attrs, "chargingStation", id);
     157        11686 :     double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
     158        11686 :     double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
     159        11686 :     const double chargingPower = attrs.getOpt<double>(SUMO_ATTR_CHARGINGPOWER, id.c_str(), ok, 22000);
     160        11686 :     const double efficiency = attrs.getOpt<double>(SUMO_ATTR_EFFICIENCY, id.c_str(), ok, 0.95);
     161        11686 :     const bool chargeInTransit = attrs.getOpt<bool>(SUMO_ATTR_CHARGEINTRANSIT, id.c_str(), ok, 0);
     162        11686 :     const SUMOTime chargeDelay = attrs.getOptSUMOTimeReporting(SUMO_ATTR_CHARGEDELAY, id.c_str(), ok, 0);
     163        23373 :     const std::string chargeType = attrs.getOpt<std::string>(SUMO_ATTR_CHARGETYPE, id.c_str(), ok, "normal");
     164        11686 :     const SUMOTime waitingTime = attrs.getOptSUMOTimeReporting(SUMO_ATTR_WAITINGTIME, id.c_str(), ok, 900);
     165        11686 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
     166        11687 :     const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
     167        23372 :     MSParkingArea* parkingArea = getParkingArea(attrs, "parkingArea", id);
     168              : 
     169              :     // check charge type
     170        11686 :     if ((chargeType != "normal") && (chargeType != "electric") && (chargeType != "fuel")) {
     171            0 :         throw InvalidArgument("The chargeType to use within MSLaneSpeedTrigger '" + id + "' is invalid.");
     172              :     }
     173              : 
     174        11686 :     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        35056 :     buildChargingStation(net, id, lane, frompos, topos, name, chargingPower, efficiency, chargeInTransit, chargeDelay, chargeType, waitingTime, parkingArea);
     179        11685 : }
     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        38722 : NLTriggerBuilder::parseAndBuildStoppingPlace(MSNet& net, const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
     486        38722 :     bool ok = true;
     487              :     // get the id, throw if not given or empty...
     488        38722 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     489        38722 :     if (!ok) {
     490            0 :         throw ProcessError();
     491              :     }
     492              : 
     493              :     //get the name, leave blank if not given
     494        77455 :     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        38722 :     RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok, RGBColor::INVISIBLE);
     499              : 
     500        77444 :     MSLane* lane = getLane(attrs, toString(element), id);
     501              :     // get the positions
     502        38722 :     double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0.);
     503        38722 :     double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
     504        38722 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
     505        38722 :     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        38730 :     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        38719 :     if (element != SUMO_TAG_CONTAINER_STOP) {
     512        28644 :         defaultCapacity = MAX2(MSStoppingPlace::getTransportablesAbreast(topos - frompos, element) * 3, 6);
     513              :         capacityAttr = SUMO_ATTR_PERSON_CAPACITY;
     514              :     } else {
     515        10075 :         defaultCapacity = MSStoppingPlace::getTransportablesAbreast(topos - frompos, element);
     516              :         capacityAttr = SUMO_ATTR_CONTAINER_CAPACITY;
     517              :     }
     518        38719 :     const int transportableCapacity = attrs.getOpt<int>(capacityAttr, id.c_str(), ok, defaultCapacity);
     519        38719 :     const double parkingLength = attrs.getOpt<double>(SUMO_ATTR_PARKING_LENGTH, id.c_str(), ok, 0);
     520              :     // build the bus stop
     521       154884 :     buildStoppingPlace(net, id, lines, lane, frompos, topos, element, ptStopName, transportableCapacity, parkingLength, color);
     522        77430 : }
     523              : 
     524              : 
     525              : void
     526         2184 : NLTriggerBuilder::addAccess(MSNet& /* net */, const SUMOSAXAttributes& attrs) {
     527         2184 :     if (myCurrentStop == nullptr) {
     528           30 :         throw InvalidArgument("Could not add access outside a stopping place.");
     529              :     }
     530              :     // get the lane
     531         4338 :     MSLane* lane = getLane(attrs, "access", myCurrentStop->getID());
     532         2169 :     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         2169 :     bool ok = true;
     538         2169 :     const std::string accessPos = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, "access", ok);
     539         2169 :     const bool random = accessPos == "random";
     540              :     MSStoppingPlace::AccessExit exit = MSStoppingPlace::AccessExit::PLATFORM;
     541         2169 :     if (accessPos == "doors") {
     542              :         exit = MSStoppingPlace::AccessExit::DOORS;
     543         2137 :     } else if (accessPos == "carriage") {
     544              :         exit = MSStoppingPlace::AccessExit::CARRIAGE;
     545              :     }
     546         2169 :     double startPos = random || exit != MSStoppingPlace::AccessExit::PLATFORM ? 0. : attrs.getOpt<double>(SUMO_ATTR_POSITION, "access", ok, 0);
     547         2169 :     double endPos = random || exit != MSStoppingPlace::AccessExit::PLATFORM ? lane->getLength() : startPos;
     548         2169 :     const double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "access", ok, -1);
     549         2169 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, "access", ok, false);
     550         2169 :     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         2169 :     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        13285 : NLTriggerBuilder::parseAndBeginParkingArea(MSNet& net, const SUMOSAXAttributes& attrs) {
     562        13285 :     bool ok = true;
     563              :     // get the id, throw if not given or empty...
     564        13285 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     565        13285 :     if (!ok) {
     566            0 :         throw ProcessError();
     567              :     }
     568              :     // get the lane
     569        26570 :     MSLane* lane = getLane(attrs, "parkingArea", id);
     570              :     // get the positions
     571        13285 :     double frompos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0);
     572        13285 :     double topos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, lane->getLength());
     573        13285 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
     574        13285 :     unsigned int capacity = attrs.getOpt<int>(SUMO_ATTR_ROADSIDE_CAPACITY, id.c_str(), ok, 0);
     575        13285 :     myParkingAreaCapacitySet = attrs.hasAttribute(SUMO_ATTR_ROADSIDE_CAPACITY);
     576        13285 :     bool onRoad = attrs.getOpt<bool>(SUMO_ATTR_ONROAD, id.c_str(), ok, false);
     577        13285 :     double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, id.c_str(), ok, 0);
     578        13285 :     double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, id.c_str(), ok, 0);
     579        13285 :     double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, id.c_str(), ok, 0);
     580        26571 :     const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok);
     581        26571 :     const std::string departPos = attrs.getOpt<std::string>(SUMO_ATTR_DEPARTPOS, id.c_str(), ok);
     582        13285 :     bool lefthand = attrs.getOpt<bool>(SUMO_ATTR_LEFTHAND, id.c_str(), ok, false);
     583        13286 :     const std::vector<std::string>& acceptedBadges = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_ACCEPTED_BADGES, id.c_str(), ok);
     584              : 
     585        13285 :     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        13284 :     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        13284 :     beginParkingArea(net, id, lines, acceptedBadges, lane, frompos, topos, capacity, width, length, angle, name, onRoad, departPos, lefthand);
     591        26569 : }
     592              : 
     593              : 
     594              : 
     595              : void
     596          600 : NLTriggerBuilder::parseAndAddLotEntry(const SUMOSAXAttributes& attrs) {
     597          600 :     bool ok = true;
     598              :     // Check for open parking area
     599          600 :     if (myParkingArea == nullptr) {
     600            0 :         throw ProcessError();
     601              :     }
     602              :     // get the positions
     603          600 :     double x = attrs.get<double>(SUMO_ATTR_X, "", ok);
     604          600 :     if (!ok) {
     605            0 :         throw InvalidArgument("Invalid x position for lot entry.");
     606              :     }
     607          600 :     double y = attrs.get<double>(SUMO_ATTR_Y, "", ok);
     608          600 :     if (!ok) {
     609            0 :         throw InvalidArgument("Invalid y position for lot entry.");
     610              :     }
     611          600 :     double z = attrs.getOpt<double>(SUMO_ATTR_Z, "", ok, 0.);
     612          600 :     double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, "", ok, myParkingArea->getWidth());
     613          600 :     double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "", ok, myParkingArea->getLength());
     614          600 :     double angle = attrs.getOpt<double>(SUMO_ATTR_ANGLE, "", ok, myParkingArea->getAngle());
     615          600 :     double slope = attrs.getOpt<double>(SUMO_ATTR_SLOPE, "", ok, 0.);
     616              :     // add the lot entry
     617          600 :     addLotEntry(x, y, z, width, length, angle, slope);
     618          600 : }
     619              : 
     620              : 
     621              : void
     622          863 : NLTriggerBuilder::parseAndBuildCalibrator(MSNet& net, const SUMOSAXAttributes& attrs,
     623              :         const std::string& base) {
     624          863 :     bool ok = true;
     625              :     // get the id, throw if not given or empty...
     626          863 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     627          863 :     if (!ok) {
     628            0 :         throw ProcessError();
     629              :     }
     630              :     MSLane* lane = nullptr;
     631              :     MSEdge* edge = nullptr;
     632              :     MSJunction* node = nullptr;
     633          863 :     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          849 :         if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
     644          419 :             const std::string edgeID = attrs.get<std::string>(SUMO_ATTR_EDGE, id.c_str(), ok);
     645          419 :             edge = MSEdge::dictionary(edgeID);
     646          419 :             if (edge == nullptr) {
     647            0 :                 throw InvalidArgument("The edge " + edgeID + " to use within the calibrator '" + id + "' is not known.");
     648              :             }
     649          419 :             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          860 :             lane = getLane(attrs, "calibrator", id);
     658              :             edge = &lane->getEdge();
     659              :         }
     660              :     }
     661          863 :     const double pos = node != nullptr ? 0 : getPosition(attrs, lane, "calibrator", id, edge);
     662          862 :     const SUMOTime period = attrs.getOptPeriod(id.c_str(), ok, DELTA_T); // !!! no error handling
     663          863 :     const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
     664          862 :     const std::string file = getFileName(attrs, base, true);
     665          862 :     const std::string outfile = attrs.getOpt<std::string>(SUMO_ATTR_OUTPUT, id.c_str(), ok, "");
     666          862 :     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         1640 :     const double invalidJamThreshold = attrs.getOpt<double>(SUMO_ATTR_JAM_DIST_THRESHOLD, id.c_str(), ok, MSGlobals::gUseMesoSim ? 0.8 : 0.5);
     669          862 :     const bool local = attrs.getOpt<bool>(SUMO_ATTR_LOCAL, id.c_str(), ok, false);
     670              :     MSRouteProbe* probe = nullptr;
     671          862 :     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          862 :     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          778 :         MSCalibrator* trigger = buildCalibrator(id, edge, lane, node, pos, file, outfile, period, probe, invalidJamThreshold, vTypes, local);
     689          778 :         if (file == "") {
     690          748 :             trigger->registerParent(SUMO_TAG_CALIBRATOR, myHandler);
     691              :         }
     692              :     }
     693          862 : }
     694              : 
     695              : 
     696              : void
     697         3384 : NLTriggerBuilder::parseAndBuildRerouter(MSNet& net, const SUMOSAXAttributes& attrs) {
     698         3384 :     bool ok = true;
     699              :     // get the id, throw if not given or empty...
     700         3384 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     701         3384 :     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         7888 :     for (const std::string& edgeID : attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, id.c_str(), ok)) {
     709         4511 :         MSEdge* edge = MSEdge::dictionary(edgeID);
     710         4511 :         if (edge == nullptr) {
     711            0 :             throw InvalidArgument("The edge '" + edgeID + "' to use within rerouter '" + id + "' is not known.");
     712              :         }
     713         4511 :         edges.push_back(edge);
     714         3377 :     }
     715         3377 :     if (!ok) {
     716            0 :         throw InvalidArgument("The edge to use within rerouter '" + id + "' is not known.");
     717              :     }
     718         3377 :     if (edges.size() == 0) {
     719            0 :         throw InvalidArgument("No edges found for rerouter '" + id + "'.");
     720              :     }
     721         3377 :     const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, id.c_str(), ok, 1);
     722         3377 :     const bool off = attrs.getOpt<bool>(SUMO_ATTR_OFF, id.c_str(), ok, false);
     723         3377 :     const bool optional = attrs.getOpt<bool>(SUMO_ATTR_OPTIONAL, id.c_str(), ok, false);
     724         3377 :     const SUMOTime timeThreshold = TIME2STEPS(attrs.getOpt<double>(SUMO_ATTR_HALTING_TIME_THRESHOLD, id.c_str(), ok, 0));
     725         3377 :     const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
     726         3377 :     const std::string pos = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, id.c_str(), ok, "");
     727         3377 :     Position p = Position::INVALID;
     728         3377 :     if (pos != "") {
     729          609 :         const std::vector<std::string> posSplit = StringTokenizer(pos, ",").getVector();
     730          203 :         if (posSplit.size() == 1) {
     731            4 :             p = edges.front()->getLanes()[0]->geometryPositionAtOffset(StringUtils::toDouble(posSplit[0]));
     732          201 :         } else if (posSplit.size() == 2) {
     733          201 :             p = Position(StringUtils::toDouble(posSplit[0]), StringUtils::toDouble(posSplit[1]));
     734            0 :         } else if (posSplit.size() == 3) {
     735            0 :             p = Position(StringUtils::toDouble(posSplit[0]), StringUtils::toDouble(posSplit[1]), StringUtils::toDouble(posSplit[2]));
     736              :         } else {
     737            0 :             throw InvalidArgument("Invalid position for rerouter '" + id + "'.");
     738              :         }
     739          203 :     }
     740         3377 :     if (!ok) {
     741            0 :         throw InvalidArgument("Could not parse rerouter '" + id + "'.");
     742              :     }
     743         3377 :     MSTriggeredRerouter* trigger = buildRerouter(net, id, edges, prob, off, optional, timeThreshold, vTypes, p);
     744              :     // read in the trigger description
     745         3377 :     trigger->registerParent(SUMO_TAG_REROUTER, myHandler);
     746         6754 : }
     747              : 
     748              : 
     749              : // -------------------------
     750              : 
     751              : 
     752              : MSLaneSpeedTrigger*
     753          377 : NLTriggerBuilder::buildLaneSpeedTrigger(MSNet& /*net*/, const std::string& id,
     754              :                                         const std::vector<MSLane*>& destLanes,
     755              :                                         const std::string& file) {
     756          377 :     return new MSLaneSpeedTrigger(id, destLanes, file);
     757              : }
     758              : 
     759              : 
     760              : METriggeredCalibrator*
     761           84 : NLTriggerBuilder::buildMECalibrator(const std::string& id,
     762              :                                     MSEdge* edge,
     763              :                                     double pos,
     764              :                                     const std::string& file,
     765              :                                     const std::string& outfile,
     766              :                                     const SUMOTime freq,
     767              :                                     MSRouteProbe* probe,
     768              :                                     const double invalidJamThreshold,
     769              :                                     const std::string& vTypes) {
     770              :     return new METriggeredCalibrator(id, edge, pos, file, outfile, freq,
     771           80 :                                      edge == nullptr ? 0. : MSGlobals::gMesoNet->getSegmentForEdge(*edge, pos)->getLength(),
     772          164 :                                      probe, invalidJamThreshold, vTypes);
     773              : }
     774              : 
     775              : 
     776              : MSCalibrator*
     777          778 : NLTriggerBuilder::buildCalibrator(const std::string& id,
     778              :                                   MSEdge* edge,
     779              :                                   MSLane* lane,
     780              :                                   MSJunction* node,
     781              :                                   double pos,
     782              :                                   const std::string& file,
     783              :                                   const std::string& outfile,
     784              :                                   const SUMOTime freq,
     785              :                                   const MSRouteProbe* probe,
     786              :                                   const double invalidJamThreshold,
     787              :                                   const std::string& vTypes,
     788              :                                   const bool local) {
     789              :     return new MSCalibrator(id, edge, lane, node, pos, file, outfile, freq,
     790              :                             edge == nullptr ? 0. : edge->getLength(),
     791         1546 :                             probe, invalidJamThreshold, vTypes, local, true);
     792              : }
     793              : 
     794              : 
     795              : MSTriggeredRerouter*
     796         2716 : NLTriggerBuilder::buildRerouter(MSNet&, const std::string& id,
     797              :                                 MSEdgeVector& edges, double prob, bool off, bool optional,
     798              :                                 SUMOTime timeThreshold, const std::string& vTypes, const Position& pos) {
     799         2716 :     return new MSTriggeredRerouter(id, edges, prob, off, optional, timeThreshold, vTypes, pos);
     800              : }
     801              : 
     802              : 
     803              : void
     804        37034 : NLTriggerBuilder::buildStoppingPlace(MSNet& net, std::string id, std::vector<std::string> lines, MSLane* lane,
     805              :                                      double frompos, double topos, const SumoXMLTag element, std::string ptStopName,
     806              :                                      int personCapacity, double parkingLength, RGBColor& color) {
     807        74068 :     myCurrentStop = new MSStoppingPlace(id, element, lines, *lane, frompos, topos, ptStopName, personCapacity, parkingLength, color);
     808        37034 :     if (!net.addStoppingPlace(element, myCurrentStop)) {
     809            5 :         delete myCurrentStop;
     810            5 :         myCurrentStop = nullptr;
     811           10 :         throw InvalidArgument("Could not build " + toString(element) + " '" + id + "'; probably declared twice.");
     812              :     }
     813        37029 : }
     814              : 
     815              : 
     816              : void
     817        12577 : NLTriggerBuilder::beginParkingArea(MSNet& net, const std::string& id,
     818              :                                    const std::vector<std::string>& lines,
     819              :                                    const std::vector<std::string>& badges,
     820              :                                    MSLane* lane, double frompos, double topos,
     821              :                                    unsigned int capacity,
     822              :                                    double width, double length, double angle, const std::string& name,
     823              :                                    bool onRoad,
     824              :                                    const std::string& departPos,
     825              :                                    bool lefthand) {
     826              :     // Close previous parking area if there are no lots inside
     827        12577 :     MSParkingArea* stop = new MSParkingArea(id, lines, badges, *lane, frompos, topos, capacity, width, length, angle, name, onRoad, departPos, lefthand);
     828        12577 :     if (!net.addStoppingPlace(SUMO_TAG_PARKING_AREA, stop)) {
     829            0 :         delete stop;
     830            0 :         throw InvalidArgument("Could not build parking area '" + id + "'; probably declared twice.");
     831              :     } else {
     832        12577 :         myParkingArea = stop;
     833              :     }
     834        12577 : }
     835              : 
     836              : 
     837              : void
     838          600 : NLTriggerBuilder::addLotEntry(double x, double y, double z,
     839              :                               double width, double length,
     840              :                               double angle, double slope) {
     841          600 :     if (myParkingArea != nullptr) {
     842          600 :         if (!myParkingArea->parkOnRoad()) {
     843          600 :             myParkingArea->addLotEntry(x, y, z, width, length, angle, slope);
     844          600 :             myParkingAreaCapacitySet = true;
     845              :         } else {
     846            0 :             throw InvalidArgument("Cannot not add lot entry to on-road parking area.");
     847              :         }
     848              :     } else {
     849            0 :         throw InvalidArgument("Could not add lot entry outside a parking area.");
     850              :     }
     851          600 : }
     852              : 
     853              : 
     854              : void
     855        12578 : NLTriggerBuilder::endParkingArea() {
     856        12578 :     if (myParkingArea != nullptr) {
     857        12577 :         myParkingArea = nullptr;
     858        12577 :         myParkingAreaCapacitySet = false;
     859              :     } else {
     860            2 :         throw InvalidArgument("Could not end a parking area that is not opened.");
     861              :     }
     862        12577 : }
     863              : 
     864              : 
     865              : void
     866        48475 : NLTriggerBuilder::endStoppingPlace() {
     867        48475 :     if (myCurrentStop != nullptr) {
     868        48466 :         myCurrentStop = nullptr;
     869              :     } else {
     870           18 :         throw InvalidArgument("Could not end a stopping place that is not opened.");
     871              :     }
     872        48466 : }
     873              : 
     874              : 
     875              : void
     876        11437 : NLTriggerBuilder::buildChargingStation(MSNet& net, const std::string& id, MSLane* lane, double frompos, double topos,
     877              :                                        const std::string& name, double chargingPower, double efficiency, bool chargeInTransit,
     878              :                                        SUMOTime chargeDelay, std::string chargeType, SUMOTime waitingTime, MSParkingArea* parkingArea) {
     879        11437 :     MSChargingStation* chargingStation = (parkingArea == nullptr) ? new MSChargingStation(id, *lane, frompos, topos, name, chargingPower, efficiency,
     880        11437 :                                          chargeInTransit, chargeDelay, chargeType, waitingTime) : new MSChargingStation(id, parkingArea, name, chargingPower, efficiency,
     881            0 :                                                  chargeInTransit, chargeDelay, chargeType, waitingTime);
     882        11437 :     if (!net.addStoppingPlace(SUMO_TAG_CHARGING_STATION, chargingStation)) {
     883            0 :         delete chargingStation;
     884            0 :         throw InvalidArgument("Could not build charging station '" + id + "'; probably declared twice.");
     885              :     }
     886        11437 :     myCurrentStop = chargingStation;
     887        11437 : }
     888              : 
     889              : 
     890              : void
     891           46 : NLTriggerBuilder::buildOverheadWireSegment(MSNet& net, const std::string& id, MSLane* lane, double frompos, double topos,
     892              :         bool voltageSource) {
     893           46 :     MSOverheadWire* overheadWireSegment = new MSOverheadWire(id, *lane, frompos, topos, voltageSource);
     894           46 :     if (!net.addStoppingPlace(SUMO_TAG_OVERHEAD_WIRE_SEGMENT, overheadWireSegment)) {
     895            0 :         delete overheadWireSegment;
     896            0 :         throw InvalidArgument("Could not build overheadWireSegment '" + id + "'; probably declared twice.");
     897              :     }
     898           46 : }
     899              : 
     900              : void
     901            4 : NLTriggerBuilder::buildInnerOverheadWireSegments(MSNet& net, const MSLane* connection, const MSLane* frontConnection, const MSLane* behindConnection) {
     902            4 :     if (frontConnection == NULL && behindConnection == NULL) {
     903            8 :         buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
     904            0 :     } else if (frontConnection != NULL && behindConnection == NULL) {
     905            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + frontConnection->getID(), const_cast<MSLane*>(frontConnection), 0, frontConnection->getLength(), false);
     906            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
     907            0 :     } else if (frontConnection == NULL && behindConnection != NULL) {
     908            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + behindConnection->getID(), const_cast<MSLane*>(behindConnection), 0, behindConnection->getLength(), false);
     909            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
     910            0 :     } else if (frontConnection != NULL && behindConnection != NULL) {
     911            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + frontConnection->getID(), const_cast<MSLane*>(frontConnection), 0, frontConnection->getLength(), false);
     912            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + behindConnection->getID(), const_cast<MSLane*>(behindConnection), 0, behindConnection->getLength(), false);
     913            0 :         buildOverheadWireSegment(net, "ovrhd_inner_" + connection->getID(), const_cast<MSLane*>(connection), 0, connection->getLength(), false);
     914              :     }
     915            4 : }
     916              : 
     917              : void
     918            8 : NLTriggerBuilder::buildTractionSubstation(MSNet& net, std::string id, double voltage, double currentLimit) {
     919            8 :     MSTractionSubstation* myTractionSubstation = new MSTractionSubstation(id, voltage, currentLimit);
     920            8 :     if (!net.addTractionSubstation(myTractionSubstation)) {
     921            0 :         delete myTractionSubstation;
     922            0 :         throw InvalidArgument("Could not build traction substation '" + id + "'; probably declared twice.");
     923              :     }
     924            8 : }
     925              : 
     926              : void
     927           10 : NLTriggerBuilder::buildOverheadWireClamp(MSNet& /*net*/, const std::string& /*id*/, MSLane* /*lane_start*/, MSLane* /*lane_end*/) {
     928           10 : }
     929              : 
     930              : std::string
     931         1339 : NLTriggerBuilder::getFileName(const SUMOSAXAttributes& attrs,
     932              :                               const std::string& base,
     933              :                               const bool allowEmpty) {
     934              :     // get the file name to read further definitions from
     935         1339 :     bool ok = true;
     936         1339 :     std::string file = attrs.getOpt<std::string>(SUMO_ATTR_FILE, nullptr, ok, "");
     937         1339 :     if (file == "") {
     938         1129 :         if (allowEmpty) {
     939         1129 :             return file;
     940              :         }
     941            0 :         throw InvalidArgument("No filename given.");
     942              :     }
     943              :     // check whether absolute or relative filenames are given
     944          210 :     if (!FileHelpers::isAbsolute(file)) {
     945          210 :         return FileHelpers::getConfigurationRelative(base, file);
     946              :     }
     947            0 :     return file;
     948              : }
     949              : 
     950              : 
     951              : MSLane*
     952        66346 : NLTriggerBuilder::getLane(const SUMOSAXAttributes& attrs,
     953              :                           const std::string& tt,
     954              :                           const std::string& tid) {
     955        66346 :     bool ok = true;
     956        66346 :     std::string objectid = attrs.get<std::string>(SUMO_ATTR_LANE, tid.c_str(), ok);
     957        66346 :     MSLane* lane = MSLane::dictionary(objectid);
     958        66346 :     if (lane == nullptr) {
     959              :         // Either a lane that is non-existent/broken, or a lane that is internal and has been ignored.
     960              :         // We assume that internal lane names start with ':'.
     961            0 :         if (objectid[0] == ':' && !MSGlobals::gUsingInternalLanes) {
     962              :             return nullptr;
     963              :         }
     964              :         // Throw the exception only in case that the lane really does not exist in the network file
     965              :         // or it is broken.
     966            0 :         throw InvalidArgument("The lane " + objectid + " to use within the " + tt + " '" + tid + "' is not known.");
     967              :     }
     968              :     return lane;
     969              : }
     970              : 
     971              : 
     972              : MSParkingArea*
     973        11686 : NLTriggerBuilder::getParkingArea(const SUMOSAXAttributes& attrs, const std::string& tt, const std::string& tid) {
     974        11686 :     bool ok = true;
     975        11686 :     std::string objectID = attrs.getOpt<std::string>(SUMO_ATTR_PARKING_AREA, tid.c_str(), ok);
     976        11686 :     if (!ok || objectID.size() == 0) {
     977              :         return nullptr;
     978              :     }
     979            0 :     MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_PARKING_AREA));
     980            0 :     if (pa == nullptr) {
     981              :         // Throw the exception only in case that the lane really does not exist in the network file
     982              :         // or it is broken.
     983            0 :         throw InvalidArgument("The parkingArea " + objectID + " to use within the " + tt + " '" + tid + "' is not known.");
     984              :     }
     985              :     return pa;
     986              : }
     987              : 
     988              : 
     989              : double
     990          849 : NLTriggerBuilder::getPosition(const SUMOSAXAttributes& attrs,
     991              :                               MSLane* lane,
     992              :                               const std::string& tt, const std::string& tid,
     993              :                               MSEdge* edge) {
     994              :     assert(lane != nullptr || edge != nullptr);
     995          849 :     const double length = lane != nullptr ? lane->getLength() : edge->getLength();
     996          849 :     bool ok = true;
     997          849 :     double pos = attrs.get<double>(SUMO_ATTR_POSITION, nullptr, ok);
     998          849 :     const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, nullptr, ok, false);
     999          849 :     if (!ok) {
    1000            0 :         throw InvalidArgument("Error on parsing a position information.");
    1001              :     }
    1002          849 :     if (pos < 0) {
    1003            2 :         pos = length + pos;
    1004              :     }
    1005          849 :     if (pos > length) {
    1006            1 :         if (friendlyPos) {
    1007            0 :             pos = length - (double) 0.1;
    1008              :         } else {
    1009            1 :             if (lane != nullptr) {
    1010            2 :                 throw InvalidArgument("The position of " + tt + " '" + tid + "' lies beyond the lane's '" + lane->getID() + "' length.");
    1011              :             } else {
    1012            0 :                 throw InvalidArgument("The position of " + tt + " '" + tid + "' lies beyond the edge's '" + edge->getID() + "' length.");
    1013              :             }
    1014              :         }
    1015              :     }
    1016          848 :     return pos;
    1017              : }
    1018              : 
    1019              : 
    1020              : void
    1021        13285 : NLTriggerBuilder::updateParkingAreaDefaultCapacity() {
    1022        13285 :     if (myParkingArea != nullptr && !myParkingAreaCapacitySet) {
    1023         9625 :         myParkingArea->setRoadsideCapacity(1);
    1024              :     }
    1025        13285 : }
    1026              : 
    1027              : 
    1028              : MSStoppingPlace*
    1029        63680 : NLTriggerBuilder::getCurrentStop() {
    1030        63680 :     return myParkingArea == nullptr ? myCurrentStop : myParkingArea;
    1031              : }
    1032              : 
    1033              : 
    1034              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1