LCOV - code coverage report
Current view: top level - src/router - ROPerson.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 95.6 % 271 259
Test Date: 2025-12-06 15:35:27 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-2025 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         3338 : ROPerson::ROPerson(const SUMOVehicleParameter& pars, const SUMOVTypeParameter* type)
      49         3338 :     : RORoutable(pars, type) {
      50         3338 : }
      51              : 
      52              : 
      53         6676 : ROPerson::~ROPerson() {
      54         6880 :     for (PlanItem* const it : myPlan) {
      55         3542 :         delete it;
      56              :     }
      57         6676 : }
      58              : 
      59              : 
      60              : void
      61         3090 : 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         3090 :     PersonTrip* trip = new PersonTrip(from, to, modeSet, departPos, stopOrigin, arrivalPos, busStop, walkFactor, group);
      68         3090 :     RONet* net = RONet::getInstance();
      69         3090 :     SUMOVehicleParameter pars;
      70         3090 :     pars.departProcedure = DepartDefinition::TRIGGERED;
      71         3090 :     if (departPos != 0) {
      72          206 :         pars.departPosProcedure = DepartPosDefinition::GIVEN;
      73          206 :         pars.departPos = departPos;
      74          206 :         pars.parametersSet |= VEHPARS_DEPARTPOS_SET;
      75              :     }
      76         6220 :     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         3090 :     }
      93         3090 :     if (trip->getVehicles().empty()) {
      94         3050 :         if ((modeSet & SVC_PASSENGER) != 0) {
      95          614 :             pars.id = id + "_0";
      96         1228 :             trip->addVehicle(new ROVehicle(pars, new RORouteDef("!" + pars.id, 0, false, false), net->getVehicleTypeSecure(DEFAULT_VTYPE_ID), net));
      97              :         }
      98         3050 :         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         3050 :         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          186 :             trip->addVehicle(new ROVehicle(pars, new RORouteDef("!" + pars.id, 0, false, false), net->getVehicleTypeSecure(DEFAULT_TAXITYPE_ID), net));
     109              :         }
     110              :     }
     111         3090 :     plan.push_back(trip);
     112         3090 : }
     113              : 
     114              : 
     115              : void
     116          100 : 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          300 :     plan.push_back(new PersonTrip(to, destStop));
     119          100 :     plan.back()->addTripItem(new Ride(-1, from, to, lines, group, -1., arrivalPos, -1., destStop));
     120          100 : }
     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          128 : ROPerson::addStop(std::vector<PlanItem*>& plan, const SUMOVehicleParameter::Stop& stopPar, const ROEdge* const stopEdge) {
     134          128 :     plan.push_back(new Stop(stopPar, stopEdge));
     135          128 : }
     136              : 
     137              : 
     138              : void
     139          880 : ROPerson::Ride::saveAsXML(OutputDevice& os, const bool extended, OptionsCont& options) const {
     140          880 :     os.openTag(SUMO_TAG_RIDE);
     141          880 :     std::string comment = "";
     142         1760 :     if ((extended || options.getBool("write-costs")) && myCost >= 0.) {
     143           20 :         os.writeAttr(SUMO_ATTR_COST, myCost);
     144              :     }
     145          880 :     if (from != nullptr) {
     146          307 :         os.writeAttr(SUMO_ATTR_FROM, from->getID());
     147              :     }
     148          880 :     if (to != nullptr) {
     149          311 :         os.writeAttr(SUMO_ATTR_TO, to->getID());
     150              :     }
     151          880 :     if (destStop != "") {
     152          669 :         const std::string element = RONet::getInstance()->getStoppingPlaceElement(destStop);
     153          669 :         os.writeAttr(element, destStop);
     154          669 :         const std::string name = RONet::getInstance()->getStoppingPlaceName(destStop);
     155          669 :         if (name != "") {
     156         1224 :             comment =  " <!-- " + name + " -->";
     157              :         }
     158          211 :     } else if (arrPos != 0 && arrPos != std::numeric_limits<double>::infinity()) {
     159           36 :         os.writeAttr(SUMO_ATTR_ARRIVALPOS, arrPos);
     160              :     }
     161          880 :     if (lines != LINE_ANY) {
     162              :         // no need to write the default
     163          247 :         os.writeAttr(SUMO_ATTR_LINES, lines);
     164              :     }
     165          880 :     if (group != "") {
     166           12 :         os.writeAttr(SUMO_ATTR_GROUP, group);
     167              :     }
     168          880 :     if (intended != "" && intended != lines) {
     169          569 :         os.writeAttr(SUMO_ATTR_INTENDED, intended);
     170              :     }
     171          880 :     if (depart >= 0) {
     172         1138 :         os.writeAttr(SUMO_ATTR_DEPART, time2string(depart));
     173              :     }
     174         1760 :     if (options.getBool("exit-times")) {
     175           24 :         os.writeAttr("started", time2string(getStart()));
     176           24 :         os.writeAttr("ended", time2string(getStart() + getDuration()));
     177              :     }
     178         1760 :     if (options.getBool("route-length") && length != -1) {
     179           24 :         os.writeAttr("routeLength", length);
     180              :     }
     181          880 :     os.closeTag(comment);
     182          880 : }
     183              : 
     184              : 
     185              : void
     186          192 : ROPerson::Stop::saveAsXML(OutputDevice& os, const bool /*extended*/, const bool /*asTrip*/, OptionsCont& /*options*/) const {
     187          192 :     stopDesc.write(os, false);
     188          192 :     std::string comment = "";
     189          312 :     for (std::string sID : stopDesc.getStoppingPlaceIDs()) {
     190          120 :         const std::string name = RONet::getInstance()->getStoppingPlaceName(sID);
     191          120 :         if (name != "") {
     192           48 :             comment += name + " ";
     193              :         }
     194          192 :     }
     195          192 :     if (comment != "") {
     196           72 :         comment =  " <!-- " + comment + " -->";
     197              :     }
     198          192 :     stopDesc.writeParams(os);
     199          192 :     os.closeTag(comment);
     200          192 : }
     201              : 
     202              : void
     203         2893 : ROPerson::Walk::saveAsXML(OutputDevice& os, const bool extended, OptionsCont& options) const {
     204         2893 :     os.openTag(SUMO_TAG_WALK);
     205         2893 :     std::string comment = "";
     206         5786 :     if ((extended || options.getBool("write-costs")) && myCost >= 0.) {
     207           32 :         os.writeAttr(SUMO_ATTR_COST, myCost);
     208              :     }
     209         2893 :     if (dur > 0) {
     210            0 :         os.writeAttr(SUMO_ATTR_DURATION, dur);
     211              :     }
     212         2893 :     if (v > 0) {
     213            0 :         os.writeAttr(SUMO_ATTR_SPEED, v);
     214              :     }
     215         2893 :     os.writeAttr(SUMO_ATTR_EDGES, edges);
     216         5786 :     if (options.getBool("exit-times")) {
     217           16 :         os.writeAttr("started", time2string(getStart()));
     218           16 :         os.writeAttr("ended", time2string(getStart() + getDuration()));
     219            8 :         if (!exitTimes.empty()) {
     220           16 :             os.writeAttr("exitTimes", exitTimes);
     221              :         }
     222              :     }
     223         5786 :     if (options.getBool("route-length")) {
     224            8 :         double length = 0;
     225           28 :         for (const ROEdge* roe : edges) {
     226              :             length += roe->getLength();
     227              :         }
     228           16 :         os.writeAttr("routeLength", length);
     229              :     }
     230         2893 :     if (destStop != "") {
     231          802 :         const std::string element = RONet::getInstance()->getStoppingPlaceElement(destStop);
     232          802 :         os.writeAttr(element, destStop);
     233          802 :         const std::string name = RONet::getInstance()->getStoppingPlaceName(destStop);
     234          802 :         if (name != "") {
     235         1731 :             comment =  " <!-- " + name + " -->";
     236              :         }
     237         2091 :     } else if (arr != 0 && arr != std::numeric_limits<double>::infinity()) {
     238          455 :         os.writeAttr(SUMO_ATTR_ARRIVALPOS, arr);
     239              :     }
     240         2893 :     os.closeTag(comment);
     241         2893 : }
     242              : 
     243              : ROPerson::PlanItem*
     244          350 : ROPerson::PersonTrip::clone() const {
     245          350 :     PersonTrip* result = new PersonTrip(from, to, modes, dep, stopOrigin, arr, stopDest, walkFactor, group);
     246          370 :     for (auto* item : myTripItems) {
     247           20 :         result->myTripItems.push_back(item->clone());
     248              :     }
     249          350 :     return result;
     250              : }
     251              : 
     252              : void
     253         3440 : ROPerson::PersonTrip::saveVehicles(OutputDevice& os, OutputDevice* const typeos, bool asAlternatives, OptionsCont& options) const {
     254         3648 :     for (ROVehicle* veh : myVehicles) {
     255          208 :         if (!RONet::getInstance()->knowsVehicle(veh->getID())) {
     256          204 :             veh->saveAsXML(os, typeos, asAlternatives, options);
     257              :         }
     258              :     }
     259         3440 : }
     260              : 
     261              : void
     262         4488 : ROPerson::PersonTrip::saveAsXML(OutputDevice& os, const bool extended, const bool asTrip, OptionsCont& options) const {
     263         4488 :     if ((asTrip || extended) && from != nullptr) {
     264         2018 :         const bool writeGeoTrip = asTrip && options.getBool("write-trips.geo");
     265         2018 :         os.openTag(SUMO_TAG_PERSONTRIP);
     266         2018 :         if (writeGeoTrip) {
     267            8 :             Position fromPos = from->getLanes()[0]->getShape().positionAtOffset2D(getDepartPos());
     268            4 :             if (GeoConvHelper::getFinal().usingGeoProjection()) {
     269            0 :                 os.setPrecision(gPrecisionGeo);
     270            0 :                 GeoConvHelper::getFinal().cartesian2geo(fromPos);
     271            0 :                 os.writeAttr(SUMO_ATTR_FROMLONLAT, fromPos);
     272            0 :                 os.setPrecision(gPrecision);
     273              :             } else {
     274            4 :                 os.writeAttr(SUMO_ATTR_FROMXY, fromPos);
     275              :             }
     276              :         } else {
     277         2014 :             os.writeAttr(SUMO_ATTR_FROM, from->getID());
     278              :         }
     279         2018 :         if (writeGeoTrip) {
     280            8 :             Position toPos = to->getLanes()[0]->getShape().positionAtOffset2D(MIN2(getArrivalPos(), to->getLanes()[0]->getShape().length2D()));
     281            4 :             if (GeoConvHelper::getFinal().usingGeoProjection()) {
     282            0 :                 os.setPrecision(gPrecisionGeo);
     283            0 :                 GeoConvHelper::getFinal().cartesian2geo(toPos);
     284            0 :                 os.writeAttr(SUMO_ATTR_TOLONLAT, toPos);
     285            0 :                 os.setPrecision(gPrecision);
     286              :             } else {
     287            4 :                 os.writeAttr(SUMO_ATTR_TOXY, toPos);
     288              :             }
     289              :         } else {
     290         2014 :             os.writeAttr(SUMO_ATTR_TO, to->getID());
     291              :         }
     292              :         std::vector<std::string> allowedModes;
     293         2018 :         if ((modes & SVC_BUS) != 0) {
     294         1560 :             allowedModes.push_back("public");
     295              :         }
     296         2018 :         if ((modes & SVC_PASSENGER) != 0) {
     297          852 :             allowedModes.push_back("car");
     298              :         }
     299         2018 :         if ((modes & SVC_TAXI) != 0) {
     300          110 :             allowedModes.push_back("taxi");
     301              :         }
     302         2018 :         if ((modes & SVC_BICYCLE) != 0) {
     303           24 :             allowedModes.push_back("bicycle");
     304              :         }
     305         2018 :         if (allowedModes.size() > 0) {
     306         1944 :             os.writeAttr(SUMO_ATTR_MODES, toString(allowedModes));
     307              :         }
     308         2018 :         if (!writeGeoTrip) {
     309         2014 :             if (dep != 0 && dep != std::numeric_limits<double>::infinity()) {
     310          133 :                 os.writeAttr(SUMO_ATTR_DEPARTPOS, dep);
     311              :             }
     312         2014 :             if (arr != 0 && arr != std::numeric_limits<double>::infinity()) {
     313          249 :                 os.writeAttr(SUMO_ATTR_ARRIVALPOS, arr);
     314              :             }
     315              :         }
     316         2018 :         if (getStopDest() != "") {
     317          104 :             os.writeAttr(SUMO_ATTR_BUS_STOP, getStopDest());
     318              :         }
     319         2018 :         if (walkFactor != 1) {
     320         2018 :             os.writeAttr(SUMO_ATTR_WALKFACTOR, walkFactor);
     321              :         }
     322         2018 :         if (extended && myTripItems.size() != 0) {
     323              :             std::vector<double> costs;
     324         2374 :             for (const TripItem* const tripItem : myTripItems) {
     325         1390 :                 costs.push_back(tripItem->getCost());
     326              :             }
     327          984 :             os.writeAttr(SUMO_ATTR_COSTS, costs);
     328          984 :         }
     329         2018 :         os.closeTag();
     330         2018 :     } else {
     331         6243 :         for (const TripItem* const it : myTripItems) {
     332         3773 :             it->saveAsXML(os, extended, options);
     333              :         }
     334              :     }
     335         4488 : }
     336              : 
     337              : SUMOTime
     338         3405 : ROPerson::PersonTrip::getDuration() const {
     339              :     SUMOTime result = 0;
     340         8570 :     for (TripItem* tItem : myTripItems) {
     341         5165 :         result += tItem->getDuration();
     342              :     }
     343         3405 :     return result;
     344              : }
     345              : 
     346              : bool
     347         3237 : ROPerson::computeIntermodal(SUMOTime time, const RORouterProvider& provider,
     348              :                             const PersonTrip* const trip, const ROVehicle* const veh,
     349              :                             std::vector<TripItem*>& resultItems, MsgHandler* const errorHandler) {
     350         3237 :     const double speed = getMaxSpeed() * trip->getWalkFactor();
     351              :     std::vector<ROIntermodalRouter::TripItem> result;
     352         3237 :     provider.getIntermodalRouter().compute(trip->getOrigin(), trip->getDestination(),
     353              :                                            trip->getDepartPos(), trip->getStopOrigin(),
     354         3237 :                                            trip->getArrivalPos(), trip->getStopDest(),
     355              :                                            speed, veh, *getType(), trip->getModes(), time, result);
     356              :     bool carUsed = false;
     357              :     SUMOTime start = time;
     358              :     int index = 0;
     359         3237 :     const int lastIndex = (int)result.size() - 1;
     360         8314 :     for (const ROIntermodalRouter::TripItem& item : result) {
     361         5077 :         if (!item.edges.empty()) {
     362         4993 :             if (item.line == "") {
     363              :                 double depPos = trip->getDepartPos(false);
     364              :                 double arrPos = trip->getArrivalPos(false);
     365         4033 :                 if (trip->getOrigin()->isTazConnector()) {
     366              :                     // walk the whole length of the first edge
     367          480 :                     const ROEdge* first = item.edges.front();
     368          480 :                     if (std::find(first->getPredecessors().begin(), first->getPredecessors().end(), trip->getOrigin()) != first->getPredecessors().end()) {
     369              :                         depPos = 0;
     370              :                     } else {
     371              :                         depPos = first->getLength();
     372              :                     }
     373              :                 }
     374         4033 :                 if (trip->getDestination()->isTazConnector()) {
     375              :                     // walk the whole length of the last edge
     376          476 :                     const ROEdge* last = item.edges.back();
     377          476 :                     if (std::find(last->getSuccessors().begin(), last->getSuccessors().end(), trip->getDestination()) != last->getSuccessors().end()) {
     378              :                         arrPos = last->getLength();
     379              :                     } else {
     380              :                         arrPos = 0;
     381              :                     }
     382              :                 }
     383         4033 :                 if (&item == &result.back() && trip->getStopDest() == "") {
     384         5876 :                     resultItems.push_back(new Walk(start, item.edges, item.cost, item.exitTimes, depPos, arrPos));
     385              :                 } else {
     386         1095 :                     resultItems.push_back(new Walk(start, item.edges, item.cost, item.exitTimes, depPos, arrPos, item.destStop));
     387              :                 }
     388          960 :             } else if (veh != nullptr && item.line == veh->getID()) {
     389          174 :                 double cost = item.cost;
     390          174 :                 if (veh->getVClass() != SVC_TAXI) {
     391          116 :                     RORoute* route = new RORoute(veh->getID() + "_RouteDef", item.edges);
     392          116 :                     route->setProbability(1);
     393          116 :                     veh->getRouteDefinition()->addLoadedAlternative(route);
     394              :                     carUsed = true;
     395           58 :                 } else if (resultItems.empty()) {
     396              :                     // if this is the first plan item the initial taxi waiting time wasn't added yet
     397           38 :                     const double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
     398           38 :                     cost += taxiWait;
     399              :                 }
     400          174 :                 double arrPos = index == lastIndex ? trip->getArrivalPos(false) : item.arrivalPos;
     401          348 :                 resultItems.push_back(new Ride(start, item.edges.front(), item.edges.back(), veh->getID(), trip->getGroup(), cost, arrPos, item.length, item.destStop));
     402              :             } else {
     403              :                 // write origin for first element of the plan
     404          786 :                 const ROEdge* origin = trip == myPlan.front() && resultItems.empty() ? trip->getOrigin() : nullptr;
     405          786 :                 const std::string line = OptionsCont::getOptions().getBool("persontrip.ride-public-line") ? item.line : LINE_ANY;
     406          786 :                 resultItems.push_back(new Ride(start, origin, nullptr, line, trip->getGroup(), item.cost, item.arrivalPos, item.length, item.destStop, item.intended, TIME2STEPS(item.depart)));
     407              :             }
     408              :         }
     409         5077 :         start += TIME2STEPS(item.cost);
     410         5077 :         index++;
     411              :     }
     412         3237 :     if (result.empty()) {
     413          138 :         errorHandler->inform("No route for trip in person '" + getID() + "'.");
     414           69 :         myRoutingSuccess = false;
     415              :     }
     416         3237 :     return carUsed;
     417         3237 : }
     418              : 
     419              : 
     420              : void
     421         3329 : ROPerson::computeRoute(const RORouterProvider& provider,
     422              :                        const bool /* removeLoops */, MsgHandler* errorHandler) {
     423         3329 :     myRoutingSuccess = true;
     424         3329 :     SUMOTime time = getParameter().depart;
     425         6862 :     for (PlanItem* const it : myPlan) {
     426         3533 :         if (it->needsRouting()) {
     427              :             PersonTrip* trip = static_cast<PersonTrip*>(it);
     428              :             const std::vector<ROVehicle*>& vehicles = trip->getVehicles();
     429              :             std::vector<TripItem*> resultItems;
     430              :             std::vector<TripItem*> best;
     431              :             const ROVehicle* bestVeh = nullptr;
     432         3229 :             if (vehicles.empty()) {
     433         2519 :                 computeIntermodal(time, provider, trip, nullptr, best, errorHandler);
     434              :             } else {
     435              :                 double bestCost = std::numeric_limits<double>::infinity();
     436         1428 :                 for (const ROVehicle* const v : vehicles) {
     437          718 :                     const bool carUsed = computeIntermodal(time, provider, trip, v, resultItems, errorHandler);
     438              :                     double cost = 0.;
     439         1546 :                     for (const TripItem* const tripIt : resultItems) {
     440          828 :                         cost += tripIt->getCost();
     441              :                     }
     442          718 :                     if (cost < bestCost) {
     443              :                         bestCost = cost;
     444          710 :                         bestVeh = carUsed ? v : nullptr;
     445              :                         best.swap(resultItems);
     446              :                     }
     447          726 :                     for (const TripItem* const tripIt : resultItems) {
     448            8 :                         delete tripIt;
     449              :                     }
     450              :                     resultItems.clear();
     451              :                 }
     452              :             }
     453         3229 :             trip->setItems(best, bestVeh);
     454         3229 :         }
     455         3533 :         time += it->getDuration();
     456              :     }
     457         3329 : }
     458              : 
     459              : 
     460              : void
     461         4400 : ROPerson::saveAsXML(OutputDevice& os, OutputDevice* const typeos, bool asAlternatives, OptionsCont& options, int cloneIndex) const {
     462              :     // write the person's vehicles
     463         8800 :     const bool writeTrip = options.exists("write-trips") && options.getBool("write-trips");
     464         8800 :     const bool writeFlow = options.exists("keep-flows") && options.getBool("keep-flows") && isPartOfFlow();
     465         4400 :     if (!writeTrip) {
     466         6990 :         for (const PlanItem* const it : myPlan) {
     467         3604 :             it->saveVehicles(os, typeos, asAlternatives, options);
     468              :         }
     469              :     }
     470              : 
     471         4400 :     if (typeos != nullptr && getType() != nullptr && !getType()->saved) {
     472           74 :         getType()->write(*typeos);
     473           74 :         getType()->saved = true;
     474              :     }
     475         4400 :     if (getType() != nullptr && !getType()->saved) {
     476         1162 :         getType()->write(os);
     477         1162 :         getType()->saved = asAlternatives;
     478              :     }
     479         4400 :     const SumoXMLTag tag = writeFlow ? SUMO_TAG_PERSONFLOW : SUMO_TAG_PERSON;
     480              :     // write the person
     481         4400 :     if (cloneIndex == 0) {
     482         8736 :         getParameter().write(os, options, tag);
     483              :     } else {
     484           32 :         SUMOVehicleParameter p = getParameter();
     485              :         // @note id collisions may occur if scale-suffic occurs in other vehicle ids
     486           64 :         p.id += options.getString("scale-suffix") + toString(cloneIndex);
     487           32 :         p.write(os, options, tag);
     488           32 :     }
     489              : 
     490         9080 :     for (const PlanItem* const it : myPlan) {
     491         4680 :         it->saveAsXML(os, asAlternatives, writeTrip, options);
     492              :     }
     493              : 
     494              :     // write params
     495         4400 :     getParameter().writeParams(os);
     496         4400 :     os.closeTag();
     497         4400 : }
     498              : 
     499              : 
     500              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1