LCOV - code coverage report
Current view: top level - src/router - ROPerson.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.1 % 254 244
Test Date: 2024-12-21 15:45:41 Functions: 100.0 % 17 17

            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    ROPerson.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/StringTokenizer.h>
      28              : #include <utils/common/ToString.h>
      29              : #include <utils/common/StringUtils.h>
      30              : #include <utils/common/MsgHandler.h>
      31              : #include <utils/geom/GeoConvHelper.h>
      32              : #include <utils/vehicle/SUMOVTypeParameter.h>
      33              : #include <utils/options/OptionsCont.h>
      34              : #include <utils/iodevices/OutputDevice.h>
      35              : #include "RORouteDef.h"
      36              : #include "RORoute.h"
      37              : #include "ROVehicle.h"
      38              : #include "ROHelper.h"
      39              : #include "RONet.h"
      40              : #include "ROLane.h"
      41              : #include "ROPerson.h"
      42              : 
      43              : const std::string ROPerson::PlanItem::UNDEFINED_STOPPING_PLACE;
      44              : 
      45              : // ===========================================================================
      46              : // method definitions
      47              : // ===========================================================================
      48         1703 : ROPerson::ROPerson(const SUMOVehicleParameter& pars, const SUMOVTypeParameter* type)
      49         1703 :     : RORoutable(pars, type) {
      50         1703 : }
      51              : 
      52              : 
      53         3406 : ROPerson::~ROPerson() {
      54         3526 :     for (PlanItem* const it : myPlan) {
      55         1823 :         delete it;
      56              :     }
      57         3406 : }
      58              : 
      59              : 
      60              : void
      61         1247 : ROPerson::addTrip(std::vector<PlanItem*>& plan, const std::string& id,
      62              :                   const ROEdge* const from, const ROEdge* const to, const SVCPermissions modeSet,
      63              :                   const std::string& vTypes,
      64              :                   const double departPos, const std::string& stopOrigin,
      65              :                   const double arrivalPos, const std::string& busStop,
      66              :                   double walkFactor, const std::string& group) {
      67         1247 :     PersonTrip* trip = new PersonTrip(from, to, modeSet, departPos, stopOrigin, arrivalPos, busStop, walkFactor, group);
      68         1247 :     RONet* net = RONet::getInstance();
      69         1247 :     SUMOVehicleParameter pars;
      70         1247 :     pars.departProcedure = DepartDefinition::TRIGGERED;
      71         1247 :     if (departPos != 0) {
      72           96 :         pars.departPosProcedure = DepartPosDefinition::GIVEN;
      73           96 :         pars.departPos = departPos;
      74           96 :         pars.parametersSet |= VEHPARS_DEPARTPOS_SET;
      75              :     }
      76         2534 :     for (StringTokenizer st(vTypes); st.hasNext();) {
      77           40 :         pars.vtypeid = st.next();
      78           40 :         pars.parametersSet |= VEHPARS_VTYPE_SET;
      79           40 :         const SUMOVTypeParameter* type = net->getVehicleTypeSecure(pars.vtypeid);
      80           40 :         if (type == nullptr) {
      81            0 :             delete trip;
      82            0 :             throw InvalidArgument("The vehicle type '" + pars.vtypeid + "' in a trip for person '" + id + "' is not known.");
      83              :         }
      84           80 :         pars.id = id + "_" + toString(trip->getVehicles().size());
      85           80 :         trip->addVehicle(new ROVehicle(pars, new RORouteDef("!" + pars.id, 0, false, false), type, net));
      86              :         // update modeset with routing-category vClass
      87           40 :         if (type->vehicleClass == SVC_BICYCLE) {
      88              :             trip->updateModes(SVC_BICYCLE);
      89              :         } else {
      90              :             trip->updateModes(SVC_PASSENGER);
      91              :         }
      92         1247 :     }
      93         1247 :     if (trip->getVehicles().empty()) {
      94         1207 :         if ((modeSet & SVC_PASSENGER) != 0) {
      95          390 :             pars.id = id + "_0";
      96          780 :             trip->addVehicle(new ROVehicle(pars, new RORouteDef("!" + pars.id, 0, false, false), net->getVehicleTypeSecure(DEFAULT_VTYPE_ID), net));
      97              :         }
      98         1207 :         if ((modeSet & SVC_BICYCLE) != 0) {
      99           24 :             pars.id = id + "_b0";
     100              :             pars.vtypeid = DEFAULT_BIKETYPE_ID;
     101           12 :             pars.parametersSet |= VEHPARS_VTYPE_SET;
     102           24 :             trip->addVehicle(new ROVehicle(pars, new RORouteDef("!" + pars.id, 0, false, false), net->getVehicleTypeSecure(DEFAULT_BIKETYPE_ID), net));
     103              :         }
     104         1207 :         if ((modeSet & SVC_TAXI) != 0) {
     105              :             // add dummy taxi for routing (never added to output)
     106              :             pars.id = "taxi"; // id is written as 'line'
     107              :             pars.vtypeid = DEFAULT_TAXITYPE_ID;
     108           96 :             trip->addVehicle(new ROVehicle(pars, new RORouteDef("!" + pars.id, 0, false, false), net->getVehicleTypeSecure(DEFAULT_TAXITYPE_ID), net));
     109              :         }
     110              :     }
     111         1247 :     plan.push_back(trip);
     112         1247 : }
     113              : 
     114              : 
     115              : void
     116           56 : ROPerson::addRide(std::vector<PlanItem*>& plan, const ROEdge* const from, const ROEdge* const to, const std::string& lines,
     117              :                   double arrivalPos, const std::string& destStop, const std::string& group) {
     118          168 :     plan.push_back(new PersonTrip(to, destStop));
     119           56 :     plan.back()->addTripItem(new Ride(-1, from, to, lines, group, -1., arrivalPos, -1., destStop));
     120           56 : }
     121              : 
     122              : 
     123              : void
     124           72 : ROPerson::addWalk(std::vector<PlanItem*>& plan, const ConstROEdgeVector& edges, const double duration, const double speed, const double departPos, const double arrivalPos, const std::string& busStop) {
     125           72 :     if (plan.empty() || plan.back()->isStop()) {
     126          204 :         plan.push_back(new PersonTrip(edges.back(), busStop));
     127              :     }
     128           72 :     plan.back()->addTripItem(new Walk(-1, edges, -1., duration, speed, departPos, arrivalPos, busStop));
     129           72 : }
     130              : 
     131              : 
     132              : void
     133          108 : ROPerson::addStop(std::vector<PlanItem*>& plan, const SUMOVehicleParameter::Stop& stopPar, const ROEdge* const stopEdge) {
     134          108 :     plan.push_back(new Stop(stopPar, stopEdge));
     135          108 : }
     136              : 
     137              : 
     138              : void
     139          592 : ROPerson::Ride::saveAsXML(OutputDevice& os, const bool extended, OptionsCont& options) const {
     140          592 :     os.openTag(SUMO_TAG_RIDE);
     141          592 :     std::string comment = "";
     142         1184 :     if ((extended || options.getBool("write-costs")) && myCost >= 0.) {
     143           20 :         os.writeAttr(SUMO_ATTR_COST, myCost);
     144              :     }
     145          592 :     if (from != nullptr) {
     146              :         os.writeAttr(SUMO_ATTR_FROM, from->getID());
     147              :     }
     148          592 :     if (to != nullptr) {
     149              :         os.writeAttr(SUMO_ATTR_TO, to->getID());
     150              :     }
     151          592 :     if (destStop != "") {
     152          460 :         const std::string element = RONet::getInstance()->getStoppingPlaceElement(destStop);
     153              :         os.writeAttr(element, destStop);
     154          460 :         const std::string name = RONet::getInstance()->getStoppingPlaceName(destStop);
     155          460 :         if (name != "") {
     156          645 :             comment =  " <!-- " + name + " -->";
     157              :         }
     158          132 :     } else if (arrPos != 0 && arrPos != std::numeric_limits<double>::infinity()) {
     159           36 :         os.writeAttr(SUMO_ATTR_ARRIVALPOS, arrPos);
     160              :     }
     161          592 :     os.writeAttr(SUMO_ATTR_LINES, lines);
     162          592 :     if (group != "") {
     163              :         os.writeAttr(SUMO_ATTR_GROUP, group);
     164              :     }
     165          592 :     if (intended != "" && intended != lines) {
     166              :         os.writeAttr(SUMO_ATTR_INTENDED, intended);
     167              :     }
     168          592 :     if (depart >= 0) {
     169          720 :         os.writeAttr(SUMO_ATTR_DEPART, time2string(depart));
     170              :     }
     171         1184 :     if (options.getBool("exit-times")) {
     172           24 :         os.writeAttr("started", time2string(getStart()));
     173           24 :         os.writeAttr("ended", time2string(getStart() + getDuration()));
     174              :     }
     175         1184 :     if (options.getBool("route-length") && length != -1) {
     176           24 :         os.writeAttr("routeLength", length);
     177              :     }
     178          592 :     os.closeTag(comment);
     179          592 : }
     180              : 
     181              : 
     182              : void
     183          172 : ROPerson::Stop::saveAsXML(OutputDevice& os, const bool /*extended*/, const bool /*asTrip*/, OptionsCont& /*options*/) const {
     184          172 :     stopDesc.write(os, false);
     185          172 :     std::string comment = "";
     186          272 :     for (std::string sID : stopDesc.getStoppingPlaceIDs()) {
     187          100 :         const std::string name = RONet::getInstance()->getStoppingPlaceName(sID);
     188          100 :         if (name != "") {
     189           48 :             comment += name + " ";
     190              :         }
     191          172 :     }
     192          172 :     if (comment != "") {
     193           72 :         comment =  " <!-- " + comment + " -->";
     194              :     }
     195          172 :     stopDesc.writeParams(os);
     196          172 :     os.closeTag(comment);
     197          172 : }
     198              : 
     199              : void
     200         2017 : ROPerson::Walk::saveAsXML(OutputDevice& os, const bool extended, OptionsCont& options) const {
     201         2017 :     os.openTag(SUMO_TAG_WALK);
     202         2017 :     std::string comment = "";
     203         4034 :     if ((extended || options.getBool("write-costs")) && myCost >= 0.) {
     204           32 :         os.writeAttr(SUMO_ATTR_COST, myCost);
     205              :     }
     206         2017 :     if (dur > 0) {
     207            0 :         os.writeAttr(SUMO_ATTR_DURATION, dur);
     208              :     }
     209         2017 :     if (v > 0) {
     210            0 :         os.writeAttr(SUMO_ATTR_SPEED, v);
     211              :     }
     212         2017 :     os.writeAttr(SUMO_ATTR_EDGES, edges);
     213         4034 :     if (options.getBool("exit-times")) {
     214           16 :         os.writeAttr("started", time2string(getStart()));
     215           16 :         os.writeAttr("ended", time2string(getStart() + getDuration()));
     216            8 :         if (!exitTimes.empty()) {
     217           16 :             os.writeAttr("exitTimes", exitTimes);
     218              :         }
     219              :     }
     220         4034 :     if (options.getBool("route-length")) {
     221            8 :         double length = 0;
     222           28 :         for (const ROEdge* roe : edges) {
     223           20 :             length += roe->getLength();
     224              :         }
     225           16 :         os.writeAttr("routeLength", length);
     226              :     }
     227         2017 :     if (destStop != "") {
     228          522 :         const std::string element = RONet::getInstance()->getStoppingPlaceElement(destStop);
     229              :         os.writeAttr(element, destStop);
     230          522 :         const std::string name = RONet::getInstance()->getStoppingPlaceName(destStop);
     231          522 :         if (name != "") {
     232          915 :             comment =  " <!-- " + name + " -->";
     233              :         }
     234         1495 :     } else if (arr != 0 && arr != std::numeric_limits<double>::infinity()) {
     235          336 :         os.writeAttr(SUMO_ATTR_ARRIVALPOS, arr);
     236              :     }
     237         2017 :     os.closeTag(comment);
     238         2017 : }
     239              : 
     240              : ROPerson::PlanItem*
     241          392 : ROPerson::PersonTrip::clone() const {
     242          392 :     PersonTrip* result = new PersonTrip(from, to, modes, dep, stopOrigin, arr, stopDest, walkFactor, group);
     243          412 :     for (auto* item : myTripItems) {
     244           20 :         result->myTripItems.push_back(item->clone());
     245              :     }
     246          392 :     return result;
     247              : }
     248              : 
     249              : void
     250         2699 : ROPerson::PersonTrip::saveVehicles(OutputDevice& os, OutputDevice* const typeos, bool asAlternatives, OptionsCont& options) const {
     251         2899 :     for (ROVehicle* veh : myVehicles) {
     252          200 :         if (!RONet::getInstance()->knowsVehicle(veh->getID())) {
     253          196 :             veh->saveAsXML(os, typeos, asAlternatives, options);
     254              :         }
     255              :     }
     256         2699 : }
     257              : 
     258              : void
     259         2731 : ROPerson::PersonTrip::saveAsXML(OutputDevice& os, const bool extended, const bool asTrip, OptionsCont& options) const {
     260         2731 :     if ((asTrip || extended) && from != nullptr) {
     261          932 :         const bool writeGeoTrip = asTrip && options.getBool("write-trips.geo");
     262          932 :         os.openTag(SUMO_TAG_PERSONTRIP);
     263          932 :         if (writeGeoTrip) {
     264            8 :             Position fromPos = from->getLanes()[0]->getShape().positionAtOffset2D(getDepartPos());
     265            4 :             if (GeoConvHelper::getFinal().usingGeoProjection()) {
     266            0 :                 os.setPrecision(gPrecisionGeo);
     267            0 :                 GeoConvHelper::getFinal().cartesian2geo(fromPos);
     268              :                 os.writeAttr(SUMO_ATTR_FROMLONLAT, fromPos);
     269            0 :                 os.setPrecision(gPrecision);
     270              :             } else {
     271              :                 os.writeAttr(SUMO_ATTR_FROMXY, fromPos);
     272              :             }
     273              :         } else {
     274          928 :             os.writeAttr(SUMO_ATTR_FROM, from->getID());
     275              :         }
     276          932 :         if (writeGeoTrip) {
     277            8 :             Position toPos = to->getLanes()[0]->getShape().positionAtOffset2D(MIN2(getArrivalPos(), to->getLanes()[0]->getShape().length2D()));
     278            4 :             if (GeoConvHelper::getFinal().usingGeoProjection()) {
     279            0 :                 os.setPrecision(gPrecisionGeo);
     280            0 :                 GeoConvHelper::getFinal().cartesian2geo(toPos);
     281              :                 os.writeAttr(SUMO_ATTR_TOLONLAT, toPos);
     282            0 :                 os.setPrecision(gPrecision);
     283              :             } else {
     284              :                 os.writeAttr(SUMO_ATTR_TOXY, toPos);
     285              :             }
     286              :         } else {
     287          928 :             os.writeAttr(SUMO_ATTR_TO, to->getID());
     288              :         }
     289              :         std::vector<std::string> allowedModes;
     290          932 :         if ((modes & SVC_BUS) != 0) {
     291          572 :             allowedModes.push_back("public");
     292              :         }
     293          932 :         if ((modes & SVC_PASSENGER) != 0) {
     294          404 :             allowedModes.push_back("car");
     295              :         }
     296          932 :         if ((modes & SVC_TAXI) != 0) {
     297           96 :             allowedModes.push_back("taxi");
     298              :         }
     299          932 :         if ((modes & SVC_BICYCLE) != 0) {
     300           24 :             allowedModes.push_back("bicycle");
     301              :         }
     302          932 :         if (allowedModes.size() > 0) {
     303          934 :             os.writeAttr(SUMO_ATTR_MODES, toString(allowedModes));
     304              :         }
     305          932 :         if (!writeGeoTrip) {
     306          928 :             if (dep != 0 && dep != std::numeric_limits<double>::infinity()) {
     307           68 :                 os.writeAttr(SUMO_ATTR_DEPARTPOS, dep);
     308              :             }
     309          928 :             if (arr != 0 && arr != std::numeric_limits<double>::infinity()) {
     310          120 :                 os.writeAttr(SUMO_ATTR_ARRIVALPOS, arr);
     311              :             }
     312              :         }
     313          932 :         if (getStopDest() != "") {
     314           84 :             os.writeAttr(SUMO_ATTR_BUS_STOP, getStopDest());
     315              :         }
     316          932 :         if (walkFactor != 1) {
     317          932 :             os.writeAttr(SUMO_ATTR_WALKFACTOR, walkFactor);
     318              :         }
     319          932 :         if (extended && myTripItems.size() != 0) {
     320              :             std::vector<double> costs;
     321         2186 :             for (const TripItem* const tripItem : myTripItems) {
     322         1282 :                 costs.push_back(tripItem->getCost());
     323              :             }
     324              :             os.writeAttr(SUMO_ATTR_COSTS, costs);
     325          904 :         }
     326          932 :         os.closeTag();
     327          932 :     } else {
     328         4408 :         for (const TripItem* const it : myTripItems) {
     329         2609 :             it->saveAsXML(os, extended, options);
     330              :         }
     331              :     }
     332         2731 : }
     333              : 
     334              : SUMOTime
     335         1707 : ROPerson::PersonTrip::getDuration() const {
     336              :     SUMOTime result = 0;
     337         4188 :     for (TripItem* tItem : myTripItems) {
     338         2481 :         result += tItem->getDuration();
     339              :     }
     340         1707 :     return result;
     341              : }
     342              : 
     343              : bool
     344         1575 : ROPerson::computeIntermodal(SUMOTime time, const RORouterProvider& provider,
     345              :                             const PersonTrip* const trip, const ROVehicle* const veh,
     346              :                             std::vector<TripItem*>& resultItems, MsgHandler* const errorHandler) {
     347         1575 :     const double speed = getMaxSpeed() * trip->getWalkFactor();
     348              :     std::vector<ROIntermodalRouter::TripItem> result;
     349         1575 :     provider.getIntermodalRouter().compute(trip->getOrigin(), trip->getDestination(),
     350              :                                            trip->getDepartPos(), trip->getStopOrigin(),
     351         1575 :                                            trip->getArrivalPos(), trip->getStopDest(),
     352              :                                            speed, veh, trip->getModes(), time, result);
     353              :     bool carUsed = false;
     354              :     SUMOTime start = time;
     355         3984 :     for (const ROIntermodalRouter::TripItem& item : result) {
     356         2409 :         if (!item.edges.empty()) {
     357         2345 :             if (item.line == "") {
     358              :                 double depPos = trip->getDepartPos(false);
     359              :                 double arrPos = trip->getArrivalPos(false);
     360         1845 :                 if (trip->getOrigin()->isTazConnector()) {
     361              :                     // walk the whole length of the first edge
     362          256 :                     const ROEdge* first = item.edges.front();
     363          256 :                     if (std::find(first->getPredecessors().begin(), first->getPredecessors().end(), trip->getOrigin()) != first->getPredecessors().end()) {
     364              :                         depPos = 0;
     365              :                     } else {
     366              :                         depPos = first->getLength();
     367              :                     }
     368              :                 }
     369         1845 :                 if (trip->getDestination()->isTazConnector()) {
     370              :                     // walk the whole length of the last edge
     371          256 :                     const ROEdge* last = item.edges.back();
     372          256 :                     if (std::find(last->getSuccessors().begin(), last->getSuccessors().end(), trip->getDestination()) != last->getSuccessors().end()) {
     373              :                         arrPos = last->getLength();
     374              :                     } else {
     375              :                         arrPos = 0;
     376              :                     }
     377              :                 }
     378         1845 :                 if (&item == &result.back() && trip->getStopDest() == "") {
     379         2734 :                     resultItems.push_back(new Walk(start, item.edges, item.cost, item.exitTimes, depPos, arrPos));
     380              :                 } else {
     381          478 :                     resultItems.push_back(new Walk(start, item.edges, item.cost, item.exitTimes, depPos, arrPos, item.destStop));
     382              :                 }
     383          500 :             } else if (veh != nullptr && item.line == veh->getID()) {
     384          140 :                 double cost = item.cost;
     385          140 :                 if (veh->getVClass() != SVC_TAXI) {
     386          112 :                     RORoute* route = new RORoute(veh->getID() + "_RouteDef", item.edges);
     387          112 :                     route->setProbability(1);
     388          112 :                     veh->getRouteDefinition()->addLoadedAlternative(route);
     389              :                     carUsed = true;
     390           28 :                 } else if (resultItems.empty()) {
     391              :                     // if this is the first plan item the initial taxi waiting time wasn't added yet
     392           12 :                     const double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
     393           12 :                     cost += taxiWait;
     394              :                 }
     395          280 :                 resultItems.push_back(new Ride(start, item.edges.front(), item.edges.back(), veh->getID(), trip->getGroup(), cost, item.arrivalPos, item.length, item.destStop));
     396              :             } else {
     397              :                 // write origin for first element of the plan
     398          360 :                 const ROEdge* origin = trip == myPlan.front() && resultItems.empty() ? trip->getOrigin() : nullptr;
     399          360 :                 resultItems.push_back(new Ride(start, origin, nullptr, item.line, trip->getGroup(), item.cost, item.arrivalPos, item.length, item.destStop, item.intended, TIME2STEPS(item.depart)));
     400              :             }
     401              :         }
     402         2409 :         start += TIME2STEPS(item.cost);
     403              :     }
     404         1575 :     if (result.empty()) {
     405           64 :         errorHandler->inform("No route for trip in person '" + getID() + "'.");
     406           32 :         myRoutingSuccess = false;
     407              :     }
     408         1575 :     return carUsed;
     409         1575 : }
     410              : 
     411              : 
     412              : void
     413         1695 : ROPerson::computeRoute(const RORouterProvider& provider,
     414              :                        const bool /* removeLoops */, MsgHandler* errorHandler) {
     415         1695 :     myRoutingSuccess = true;
     416         1695 :     SUMOTime time = getParameter().depart;
     417         3510 :     for (PlanItem* const it : myPlan) {
     418         1815 :         if (it->needsRouting()) {
     419              :             PersonTrip* trip = static_cast<PersonTrip*>(it);
     420              :             const std::vector<ROVehicle*>& vehicles = trip->getVehicles();
     421              :             std::vector<TripItem*> resultItems;
     422              :             std::vector<TripItem*> best;
     423              :             const ROVehicle* bestVeh = nullptr;
     424         1567 :             if (vehicles.empty()) {
     425         1105 :                 computeIntermodal(time, provider, trip, nullptr, best, errorHandler);
     426              :             } else {
     427              :                 double bestCost = std::numeric_limits<double>::infinity();
     428          932 :                 for (const ROVehicle* const v : vehicles) {
     429          470 :                     const bool carUsed = computeIntermodal(time, provider, trip, v, resultItems, errorHandler);
     430              :                     double cost = 0.;
     431         1068 :                     for (const TripItem* const tripIt : resultItems) {
     432          598 :                         cost += tripIt->getCost();
     433              :                     }
     434          470 :                     if (cost < bestCost) {
     435              :                         bestCost = cost;
     436          462 :                         bestVeh = carUsed ? v : nullptr;
     437              :                         best.swap(resultItems);
     438              :                     }
     439          478 :                     for (const TripItem* const tripIt : resultItems) {
     440            8 :                         delete tripIt;
     441              :                     }
     442              :                     resultItems.clear();
     443              :                 }
     444              :             }
     445         1567 :             trip->setItems(best, bestVeh);
     446         1567 :         }
     447         1815 :         time += it->getDuration();
     448              :     }
     449         1695 : }
     450              : 
     451              : 
     452              : void
     453         2711 : ROPerson::saveAsXML(OutputDevice& os, OutputDevice* const typeos, bool asAlternatives, OptionsCont& options, int cloneIndex) const {
     454              :     // write the person's vehicles
     455         5422 :     const bool writeTrip = options.exists("write-trips") && options.getBool("write-trips");
     456         2711 :     if (!writeTrip) {
     457         5546 :         for (const PlanItem* const it : myPlan) {
     458         2863 :             it->saveVehicles(os, typeos, asAlternatives, options);
     459              :         }
     460              :     }
     461              : 
     462         2711 :     if (typeos != nullptr && getType() != nullptr && !getType()->saved) {
     463           29 :         getType()->write(*typeos);
     464           29 :         getType()->saved = true;
     465              :     }
     466         2711 :     if (getType() != nullptr && !getType()->saved) {
     467          986 :         getType()->write(os);
     468          986 :         getType()->saved = asAlternatives;
     469              :     }
     470              : 
     471              :     // write the person
     472         2711 :     if (cloneIndex == 0) {
     473         5358 :         getParameter().write(os, options, SUMO_TAG_PERSON);
     474              :     } else {
     475           32 :         SUMOVehicleParameter p = getParameter();
     476              :         // @note id collisions may occur if scale-suffic occurs in other vehicle ids
     477           64 :         p.id += options.getString("scale-suffix") + toString(cloneIndex);
     478           32 :         p.write(os, options, SUMO_TAG_PERSON);
     479           32 :     }
     480              : 
     481         5614 :     for (const PlanItem* const it : myPlan) {
     482         2903 :         it->saveAsXML(os, asAlternatives, writeTrip, options);
     483              :     }
     484              : 
     485              :     // write params
     486         2711 :     getParameter().writeParams(os);
     487         2711 :     os.closeTag();
     488         2711 : }
     489              : 
     490              : 
     491              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1