LCOV - code coverage report
Current view: top level - src/router - ROVehicle.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 140 166 84.3 %
Date: 2024-05-08 15:29:52 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2002-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    ROVehicle.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Axel Wegener
      17             : /// @author  Michael Behrisch
      18             : /// @author  Jakob Erdmann
      19             : /// @date    Sept 2002
      20             : ///
      21             : // A vehicle as used by router
      22             : /****************************************************************************/
      23             : #include <config.h>
      24             : 
      25             : #include <string>
      26             : #include <iostream>
      27             : #include <utils/common/StringUtils.h>
      28             : #include <utils/common/ToString.h>
      29             : #include <utils/common/MsgHandler.h>
      30             : #include <utils/geom/GeoConvHelper.h>
      31             : #include <utils/vehicle/SUMOVTypeParameter.h>
      32             : #include <utils/options/OptionsCont.h>
      33             : #include <utils/iodevices/OutputDevice.h>
      34             : #include "RORouteDef.h"
      35             : #include "RORoute.h"
      36             : #include "ROHelper.h"
      37             : #include "RONet.h"
      38             : #include "ROLane.h"
      39             : #include "ROVehicle.h"
      40             : 
      41             : // ===========================================================================
      42             : // static members
      43             : // ===========================================================================
      44             : std::map<ConstROEdgeVector, std::string> ROVehicle::mySavedRoutes;
      45             : 
      46             : // ===========================================================================
      47             : // method definitions
      48             : // ===========================================================================
      49      277194 : ROVehicle::ROVehicle(const SUMOVehicleParameter& pars,
      50             :                      RORouteDef* route, const SUMOVTypeParameter* type,
      51      277194 :                      const RONet* net, MsgHandler* errorHandler):
      52             :     RORoutable(pars, type),
      53      277194 :     myRoute(route),
      54      277194 :     myJumpTime(-1) {
      55             :     getParameter().stops.clear();
      56      553582 :     if (route != nullptr && route->getFirstRoute() != nullptr) {
      57      553100 :         for (std::vector<SUMOVehicleParameter::Stop>::const_iterator s = route->getFirstRoute()->getStops().begin(); s != route->getFirstRoute()->getStops().end(); ++s) {
      58         324 :             addStop(*s, net, errorHandler);
      59             :         }
      60             :     }
      61      277653 :     for (std::vector<SUMOVehicleParameter::Stop>::const_iterator s = pars.stops.begin(); s != pars.stops.end(); ++s) {
      62         459 :         addStop(*s, net, errorHandler);
      63             :     }
      64      277194 :     if (pars.via.size() != 0) {
      65             :         // via takes precedence over stop edges
      66             :         // XXX check for inconsistencies #2275
      67             :         myStopEdges.clear();
      68       48250 :         for (std::vector<std::string>::const_iterator it = pars.via.begin(); it != pars.via.end(); ++it) {
      69             :             assert(net->getEdge(*it) != 0);
      70       33594 :             myStopEdges.push_back(net->getEdge(*it));
      71             :         }
      72             :     }
      73      277194 : }
      74             : 
      75             : 
      76             : void
      77         783 : ROVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, const RONet* net, MsgHandler* errorHandler) {
      78        1566 :     const ROEdge* stopEdge = net->getEdge(stopPar.edge);
      79             :     assert(stopEdge != 0); // was checked when parsing the stop
      80         783 :     if (stopEdge->prohibits(this)) {
      81           0 :         if (errorHandler != nullptr) {
      82           0 :             errorHandler->inform("Stop edge '" + stopEdge->getID() + "' does not allow vehicle '" + getID() + "'.");
      83             :         }
      84           0 :         return;
      85             :     }
      86             :     // where to insert the stop
      87             :     std::vector<SUMOVehicleParameter::Stop>::iterator iter = getParameter().stops.begin();
      88             :     ConstROEdgeVector::iterator edgeIter = myStopEdges.begin();
      89         783 :     if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(getParameter().stops.size())) {
      90         783 :         if (getParameter().stops.size() > 0) {
      91             :             iter = getParameter().stops.end();
      92             :             edgeIter = myStopEdges.end();
      93             :         }
      94             :     } else {
      95           0 :         if (stopPar.index == STOP_INDEX_FIT) {
      96           0 :             const ConstROEdgeVector edges = myRoute->getFirstRoute()->getEdgeVector();
      97           0 :             ConstROEdgeVector::const_iterator stopEdgeIt = std::find(edges.begin(), edges.end(), stopEdge);
      98           0 :             if (stopEdgeIt == edges.end()) {
      99             :                 iter = getParameter().stops.end();
     100             :                 edgeIter = myStopEdges.end();
     101             :             } else {
     102           0 :                 while (iter != getParameter().stops.end()) {
     103           0 :                     if (edgeIter > stopEdgeIt || (edgeIter == stopEdgeIt && iter->endPos >= stopPar.endPos)) {
     104             :                         break;
     105             :                     }
     106             :                     ++iter;
     107             :                     ++edgeIter;
     108             :                 }
     109             :             }
     110             :         } else {
     111             :             iter += stopPar.index;
     112             :             edgeIter += stopPar.index;
     113             :         }
     114             :     }
     115         783 :     getParameter().stops.insert(iter, stopPar);
     116         783 :     myStopEdges.insert(edgeIter, stopEdge);
     117         783 :     if (stopPar.jump >= 0) {
     118          24 :         if (stopEdge->isInternal()) {
     119           0 :             if (errorHandler != nullptr) {
     120           0 :                 errorHandler->inform("Jumps are not supported from internal stop edge '" + stopEdge->getID() + "'.");
     121             :             }
     122             :         } else {
     123          24 :             if (myJumpTime < 0) {
     124          20 :                 myJumpTime = 0;
     125             :             }
     126          24 :             myJumpTime += stopPar.jump;
     127             :         }
     128             :     }
     129             : }
     130             : 
     131             : 
     132      554320 : ROVehicle::~ROVehicle() {}
     133             : 
     134             : 
     135             : const ROEdge*
     136         580 : ROVehicle:: getDepartEdge() const {
     137         580 :     return myRoute->getFirstRoute()->getFirst();
     138             : }
     139             : 
     140             : 
     141             : void
     142      276172 : ROVehicle::computeRoute(const RORouterProvider& provider,
     143             :                         const bool removeLoops, MsgHandler* errorHandler) {
     144             :     SUMOAbstractRouter<ROEdge, ROVehicle>& router = provider.getVehicleRouter(getVClass());
     145      552344 :     std::string noRouteMsg = "The vehicle '" + getID() + "' has no valid route.";
     146             :     RORouteDef* const routeDef = getRouteDefinition();
     147             :     // check if the route definition is valid
     148      276172 :     if (routeDef == nullptr) {
     149           0 :         errorHandler->inform(noRouteMsg);
     150           0 :         myRoutingSuccess = false;
     151           0 :         return;
     152             :     }
     153      276172 :     RORoute* current = routeDef->buildCurrentRoute(router, getDepartureTime(), *this);
     154      276172 :     if (current == nullptr || current->size() == 0) {
     155        3408 :         delete current;
     156        3408 :         if (current == nullptr || !routeDef->discardSilent()) {
     157        2574 :             errorHandler->inform(noRouteMsg);
     158             :         }
     159        3408 :         myRoutingSuccess = false;
     160        3408 :         return;
     161             :     }
     162             :     // check whether we have to evaluate the route for not containing loops
     163      272764 :     if (removeLoops) {
     164        5112 :         const ROEdge* requiredStart = (getParameter().departPosProcedure == DepartPosDefinition::GIVEN
     165        5112 :                                        || getParameter().departLaneProcedure == DepartLaneDefinition::GIVEN ? current->getEdgeVector().front() : 0);
     166        5112 :         const ROEdge* requiredEnd = (getParameter().arrivalPosProcedure == ArrivalPosDefinition::GIVEN
     167        5112 :                                      || getParameter().arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN ? current->getEdgeVector().back() : 0);
     168       10224 :         current->recheckForLoops(getMandatoryEdges(requiredStart, requiredEnd));
     169             :         // check whether the route is still valid
     170        5112 :         if (current->size() == 0) {
     171           0 :             delete current;
     172          16 :             errorHandler->inform(noRouteMsg + " (after removing loops)");
     173           0 :             myRoutingSuccess = false;
     174           0 :             return;
     175             :         }
     176             :     }
     177             :     // add built route
     178      272764 :     routeDef->addAlternative(router, this, current, getDepartureTime());
     179      272748 :     myRoutingSuccess = true;
     180             : }
     181             : 
     182             : 
     183             : ConstROEdgeVector
     184      271785 : ROVehicle::getMandatoryEdges(const ROEdge* requiredStart, const ROEdge* requiredEnd) const {
     185             :     ConstROEdgeVector mandatory;
     186      271785 :     if (requiredStart) {
     187      266681 :         mandatory.push_back(requiredStart);
     188             :     }
     189      306026 :     for (const ROEdge* e : getStopEdges()) {
     190       34241 :         if (e->isInternal()) {
     191             :             // the edges before and after the internal edge are mandatory
     192           8 :             const ROEdge* before = e->getNormalBefore();
     193           8 :             const ROEdge* after = e->getNormalAfter();
     194           8 :             if (mandatory.size() == 0 || after != mandatory.back()) {
     195           8 :                 mandatory.push_back(before);
     196           8 :                 mandatory.push_back(after);
     197             :             }
     198             :         } else {
     199       34233 :             if (mandatory.size() == 0 || e != mandatory.back()) {
     200       28437 :                 mandatory.push_back(e);
     201             :             }
     202             :         }
     203             :     }
     204      271785 :     if (requiredEnd) {
     205      266681 :         if (mandatory.size() < 2 || mandatory.back() != requiredEnd) {
     206      264997 :             mandatory.push_back(requiredEnd);
     207             :         }
     208             :     }
     209      271785 :     return mandatory;
     210             : }
     211             : 
     212             : 
     213             : void
     214      266673 : ROVehicle::collectJumps(const ConstROEdgeVector& mandatory, std::set<ConstROEdgeVector::const_iterator>& jumpStarts) const {
     215      266673 :     auto itM = mandatory.begin();
     216             :     auto itS = getParameter().stops.begin();
     217             :     auto itSEnd = getParameter().stops.end();
     218      267559 :     while (itM != mandatory.end() && itS != itSEnd) {
     219             :         bool repeatMandatory = false;
     220             :         // if we stop twice on the same edge, we must treat this as a repeated
     221             :         // mandatory edge (even though the edge appears only once in the mandatory vector)
     222         886 :         if ((*itM)->getID() == itS->edge) {
     223         627 :             if (itS->jump >= 0) {
     224             :                 jumpStarts.insert(itM);
     225             :             }
     226             :             itS++;
     227         627 :             if (itS != itSEnd && itS->edge == (itS - 1)->edge) {
     228             :                 repeatMandatory = true;
     229             :             }
     230             :         }
     231             :         if (!repeatMandatory) {
     232             :             itM++;
     233             :         }
     234             :     }
     235      266673 : }
     236             : 
     237             : 
     238             : void
     239      480533 : ROVehicle::saveAsXML(OutputDevice& os, OutputDevice* const typeos, bool asAlternatives, OptionsCont& options) const {
     240      480533 :     if (typeos != nullptr && getType() != nullptr && !getType()->saved) {
     241         284 :         getType()->write(*typeos);
     242         284 :         getType()->saved = true;
     243             :     }
     244      480533 :     if (getType() != nullptr && !getType()->saved) {
     245        4498 :         getType()->write(os);
     246        4498 :         getType()->saved = asAlternatives;
     247             :     }
     248             : 
     249     1407119 :     const bool writeTrip = options.exists("write-trips") && options.getBool("write-trips");
     250      502879 :     const bool writeGeoTrip = writeTrip && options.getBool("write-trips.geo");
     251      495651 :     const bool writeJunctions = writeTrip && options.getBool("write-trips.junctions");
     252      753358 :     const bool writeNamedRoute = !asAlternatives && options.getBool("named-routes");
     253     1429417 :     const bool writeCosts = options.exists("write-costs") && options.getBool("write-costs");
     254     1233049 :     const bool writeExit = options.exists("exit-times") && options.getBool("exit-times");
     255     1429451 :     const bool writeLength = options.exists("route-length") && options.getBool("route-length");
     256             : 
     257             :     std::string routeID;
     258      480533 :     if (writeNamedRoute) {
     259          21 :         ConstROEdgeVector edges = myRoute->getUsedRoute()->getNormalEdges();
     260             :         auto it = mySavedRoutes.find(edges);
     261          21 :         if (it == mySavedRoutes.end()) {
     262          14 :             routeID = "r" + toString(mySavedRoutes.size());
     263           7 :             myRoute->getUsedRoute()->writeXMLDefinition(os, this, writeCosts, false, writeExit,
     264             :                     writeLength, routeID);
     265           7 :             mySavedRoutes[edges] = routeID;
     266             :         } else {
     267          14 :             routeID = it->second;
     268             :         }
     269             :     }
     270             :     // write the vehicle (new style, with included routes)
     271      938704 :     getParameter().write(os, options, writeTrip ? SUMO_TAG_TRIP : SUMO_TAG_VEHICLE);
     272             : 
     273             :     // save the route
     274      480533 :     if (writeTrip) {
     275       44724 :         const ConstROEdgeVector edges = myRoute->getFirstRoute()->getEdgeVector();
     276             :         const ROEdge* from = nullptr;
     277             :         const ROEdge* to = nullptr;
     278       22362 :         if (edges.size() > 0) {
     279       22362 :             if (edges.front()->isTazConnector()) {
     280        7256 :                 if (edges.size() > 1) {
     281        7256 :                     from = edges[1];
     282        7256 :                     if (from->isTazConnector() && writeJunctions && edges.front()->getSuccessors().size() > 0) {
     283             :                         // routing was skipped
     284           8 :                         from = edges.front()->getSuccessors(getVClass()).front();
     285             :                     }
     286             :                 }
     287             :             } else {
     288             :                 from = edges[0];
     289             :             }
     290       22362 :             if (edges.back()->isTazConnector()) {
     291        7256 :                 if (edges.size() > 1) {
     292        7256 :                     to = edges[edges.size() - 2];
     293        7256 :                     if (to->isTazConnector() && writeJunctions && edges.back()->getPredecessors().size() > 0) {
     294             :                         // routing was skipped
     295           4 :                         to = edges.back()->getPredecessors().front();
     296             :                     }
     297             :                 }
     298             :             } else {
     299       15106 :                 to = edges[edges.size() - 1];
     300             :             }
     301             :         }
     302       22362 :         if (from != nullptr) {
     303       22362 :             if (writeGeoTrip) {
     304          16 :                 Position fromPos = from->getLanes()[0]->getShape().positionAtOffset2D(0);
     305          16 :                 if (GeoConvHelper::getFinal().usingGeoProjection()) {
     306           0 :                     os.setPrecision(gPrecisionGeo);
     307           0 :                     GeoConvHelper::getFinal().cartesian2geo(fromPos);
     308             :                     os.writeAttr(SUMO_ATTR_FROMLONLAT, fromPos);
     309           0 :                     os.setPrecision(gPrecision);
     310             :                 } else {
     311             :                     os.writeAttr(SUMO_ATTR_FROMXY, fromPos);
     312             :                 }
     313       22346 :             } else if (writeJunctions) {
     314             :                 os.writeAttr(SUMO_ATTR_FROM_JUNCTION, from->getFromJunction()->getID());
     315             :             } else {
     316             :                 os.writeAttr(SUMO_ATTR_FROM, from->getID());
     317             :             }
     318             :         }
     319       22362 :         if (to != nullptr) {
     320       22362 :             if (writeGeoTrip) {
     321          16 :                 Position toPos = to->getLanes()[0]->getShape().positionAtOffset2D(to->getLanes()[0]->getShape().length2D());
     322          16 :                 if (GeoConvHelper::getFinal().usingGeoProjection()) {
     323           0 :                     os.setPrecision(gPrecisionGeo);
     324           0 :                     GeoConvHelper::getFinal().cartesian2geo(toPos);
     325             :                     os.writeAttr(SUMO_ATTR_TOLONLAT, toPos);
     326           0 :                     os.setPrecision(gPrecision);
     327             :                 } else {
     328             :                     os.writeAttr(SUMO_ATTR_TOXY, toPos);
     329             :                 }
     330       22346 :             } else if (writeJunctions) {
     331             :                 os.writeAttr(SUMO_ATTR_TO_JUNCTION, to->getToJunction()->getID());
     332             :             } else {
     333             :                 os.writeAttr(SUMO_ATTR_TO, to->getID());
     334             :             }
     335             :         }
     336       22362 :         if (getParameter().via.size() > 0) {
     337             :             std::vector<std::string> viaOut;
     338             :             SumoXMLAttr viaAttr = (writeGeoTrip
     339        7232 :                                    ? (GeoConvHelper::getFinal().usingGeoProjection() ? SUMO_ATTR_VIALONLAT : SUMO_ATTR_VIAXY)
     340        7224 :                                    : (writeJunctions ? SUMO_ATTR_VIAJUNCTIONS : SUMO_ATTR_VIA));
     341       21664 :             for (const std::string& viaID : getParameter().via) {
     342       14432 :                 const ROEdge* viaEdge = RONet::getInstance()->getEdge(viaID);
     343       14432 :                 if (viaEdge->isTazConnector()) {
     344          16 :                     if (viaEdge->getPredecessors().size() == 0) {
     345           0 :                         continue;
     346             :                     }
     347             :                     // XXX used edge that was used in route
     348          16 :                     viaEdge = viaEdge->getPredecessors().front();
     349             :                 }
     350             :                 assert(viaEdge != nullptr);
     351       14432 :                 if (writeGeoTrip) {
     352           8 :                     Position viaPos = viaEdge->getLanes()[0]->getShape().positionAtOffset2D(viaEdge->getLanes()[0]->getShape().length2D() / 2);
     353           8 :                     if (GeoConvHelper::getFinal().usingGeoProjection()) {
     354           0 :                         GeoConvHelper::getFinal().cartesian2geo(viaPos);
     355           0 :                         viaOut.push_back(toString(viaPos, gPrecisionGeo));
     356             :                     } else {
     357          16 :                         viaOut.push_back(toString(viaPos, gPrecision));
     358             :                     }
     359       14424 :                 } else if (writeJunctions) {
     360           8 :                     viaOut.push_back(viaEdge->getToJunction()->getID());
     361             :                 } else {
     362       14416 :                     viaOut.push_back(viaEdge->getID());
     363             :                 }
     364             :             }
     365             :             os.writeAttr(viaAttr, viaOut);
     366        7232 :         }
     367      458171 :     } else if (writeNamedRoute) {
     368             :         os.writeAttr(SUMO_ATTR_ROUTE, routeID);
     369             :     } else {
     370      458150 :         myRoute->writeXMLDefinition(os, this, asAlternatives, writeExit, writeCosts, writeLength);
     371             :     }
     372      481799 :     for (std::vector<SUMOVehicleParameter::Stop>::const_iterator stop = getParameter().stops.begin(); stop != getParameter().stops.end(); ++stop) {
     373        1266 :         stop->write(os);
     374             :     }
     375      480533 :     getParameter().writeParams(os);
     376      961066 :     os.closeTag();
     377      480533 : }
     378             : 
     379             : 
     380             : /****************************************************************************/

Generated by: LCOV version 1.14