1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2017-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    Simulation.cpp
11 /// @author  Laura Bieker-Walz
12 /// @author  Robert Hilbrich
13 /// @date    15.09.2017
14 /// @version $Id$
15 ///
16 // C++ TraCI client API implementation
17 /****************************************************************************/
18 
19 // ===========================================================================
20 // included modules
21 // ===========================================================================
22 #include <config.h>
23 
24 #include <utils/options/OptionsCont.h>
25 #include <utils/common/StdDefs.h>
26 #include <utils/common/StringTokenizer.h>
27 #include <utils/common/StringUtils.h>
28 #include <utils/common/SystemFrame.h>
29 #include <utils/geom/GeoConvHelper.h>
30 #include <utils/options/OptionsIO.h>
31 #include <utils/router/IntermodalRouter.h>
32 #include <utils/router/PedestrianRouter.h>
33 #include <utils/xml/XMLSubSys.h>
34 #include <microsim/MSNet.h>
35 #include <microsim/MSEdgeControl.h>
36 #include <microsim/MSInsertionControl.h>
37 #include <microsim/MSEdge.h>
38 #include <microsim/MSLane.h>
39 #include <microsim/MSVehicle.h>
40 #include <microsim/MSVehicleControl.h>
41 #include <microsim/MSTransportableControl.h>
42 #include <microsim/MSStateHandler.h>
43 #include <microsim/MSStoppingPlace.h>
44 #include <microsim/MSParkingArea.h>
45 #include <microsim/devices/MSRoutingEngine.h>
46 #include <netload/NLBuilder.h>
47 #include <libsumo/TraCIConstants.h>
48 #include "Simulation.h"
49 #include <libsumo/TraCIDefs.h>
50 
51 
52 namespace libsumo {
53 // ===========================================================================
54 // static member initializations
55 // ===========================================================================
56 SubscriptionResults Simulation::mySubscriptionResults;
57 ContextSubscriptionResults Simulation::myContextSubscriptionResults;
58 
59 
60 // ===========================================================================
61 // static member definitions
62 // ===========================================================================
63 void
load(const std::vector<std::string> & args)64 Simulation::load(const std::vector<std::string>& args) {
65     close();
66     XMLSubSys::init();
67     OptionsIO::setArgs(args);
68     NLBuilder::init();
69     Helper::registerVehicleStateListener();
70 }
71 
72 
73 bool
isLoaded()74 Simulation::isLoaded() {
75     return MSNet::hasInstance();
76 }
77 
78 
79 void
step(const double time)80 Simulation::step(const double time) {
81     Helper::clearVehicleStates();
82     const SUMOTime t = TIME2STEPS(time);
83     if (t == 0) {
84         MSNet::getInstance()->simulationStep();
85     } else {
86         while (MSNet::getInstance()->getCurrentTimeStep() < t) {
87             MSNet::getInstance()->simulationStep();
88         }
89     }
90     Helper::handleSubscriptions(t);
91 }
92 
93 
94 void
close()95 Simulation::close() {
96     if (MSNet::hasInstance()) {
97         MSNet::getInstance()->closeSimulation(0);
98         delete MSNet::getInstance();
99         XMLSubSys::close();
100         SystemFrame::close();
101     }
102 }
103 
104 
LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Simulation,SIM)105 LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Simulation, SIM)
106 
107 
108 void
109 Simulation::subscribe(const std::vector<int>& vars, double beginTime, double endTime) {
110     libsumo::Helper::subscribe(CMD_SUBSCRIBE_SIM_VARIABLE, "", vars, beginTime, endTime);
111 }
112 
113 
114 const TraCIResults
getSubscriptionResults()115 Simulation::getSubscriptionResults() {
116     return mySubscriptionResults[""];
117 }
118 
119 
120 int
getCurrentTime()121 Simulation::getCurrentTime() {
122     return (int)MSNet::getInstance()->getCurrentTimeStep();
123 }
124 
125 
126 double
getTime()127 Simulation::getTime() {
128     return SIMTIME;
129 }
130 
131 
132 int
getLoadedNumber()133 Simulation::getLoadedNumber() {
134     return (int)Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_BUILT).size();
135 }
136 
137 
138 std::vector<std::string>
getLoadedIDList()139 Simulation::getLoadedIDList() {
140     return Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_BUILT);
141 }
142 
143 
144 int
getDepartedNumber()145 Simulation::getDepartedNumber() {
146     return (int)Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_DEPARTED).size();
147 }
148 
149 
150 std::vector<std::string>
getDepartedIDList()151 Simulation::getDepartedIDList() {
152     return Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_DEPARTED);
153 }
154 
155 
156 int
getArrivedNumber()157 Simulation::getArrivedNumber() {
158     return (int)Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_ARRIVED).size();
159 }
160 
161 
162 std::vector<std::string>
getArrivedIDList()163 Simulation::getArrivedIDList() {
164     return Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_ARRIVED);
165 }
166 
167 
168 int
getParkingStartingVehiclesNumber()169 Simulation::getParkingStartingVehiclesNumber() {
170     return (int)Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_STARTING_PARKING).size();
171 }
172 
173 
174 std::vector<std::string>
getParkingStartingVehiclesIDList()175 Simulation::getParkingStartingVehiclesIDList() {
176     return Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_STARTING_PARKING);
177 }
178 
179 
180 int
getParkingEndingVehiclesNumber()181 Simulation::getParkingEndingVehiclesNumber() {
182     return (int)Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_ENDING_PARKING).size();
183 }
184 
185 
186 std::vector<std::string>
getParkingEndingVehiclesIDList()187 Simulation::getParkingEndingVehiclesIDList() {
188     return Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_ENDING_PARKING);
189 }
190 
191 
192 int
getStopStartingVehiclesNumber()193 Simulation::getStopStartingVehiclesNumber() {
194     return (int)Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_STARTING_STOP).size();
195 }
196 
197 
198 std::vector<std::string>
getStopStartingVehiclesIDList()199 Simulation::getStopStartingVehiclesIDList() {
200     return Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_STARTING_STOP);
201 }
202 
203 
204 int
getStopEndingVehiclesNumber()205 Simulation::getStopEndingVehiclesNumber() {
206     return (int)Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_ENDING_STOP).size();
207 }
208 
209 
210 std::vector<std::string>
getStopEndingVehiclesIDList()211 Simulation::getStopEndingVehiclesIDList() {
212     return Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_ENDING_STOP);
213 }
214 
215 
216 int
getCollidingVehiclesNumber()217 Simulation::getCollidingVehiclesNumber() {
218     return (int)Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_COLLISION).size();
219 }
220 
221 
222 std::vector<std::string>
getCollidingVehiclesIDList()223 Simulation::getCollidingVehiclesIDList() {
224     return Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_COLLISION);
225 }
226 
227 
228 int
getEmergencyStoppingVehiclesNumber()229 Simulation::getEmergencyStoppingVehiclesNumber() {
230     return (int)Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_EMERGENCYSTOP).size();
231 }
232 
233 
234 std::vector<std::string>
getEmergencyStoppingVehiclesIDList()235 Simulation::getEmergencyStoppingVehiclesIDList() {
236     return Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_EMERGENCYSTOP);
237 }
238 
239 
240 int
getStartingTeleportNumber()241 Simulation::getStartingTeleportNumber() {
242     return (int)Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_STARTING_TELEPORT).size();
243 }
244 
245 
246 std::vector<std::string>
getStartingTeleportIDList()247 Simulation::getStartingTeleportIDList() {
248     return Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_STARTING_TELEPORT);
249 }
250 
251 
252 int
getEndingTeleportNumber()253 Simulation::getEndingTeleportNumber() {
254     return (int)Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_ENDING_TELEPORT).size();
255 }
256 
257 
258 std::vector<std::string>
getEndingTeleportIDList()259 Simulation::getEndingTeleportIDList() {
260     return Helper::getVehicleStateChanges(MSNet::VEHICLE_STATE_ENDING_TELEPORT);
261 }
262 
263 
264 int
getBusStopWaiting(const std::string & id)265 Simulation::getBusStopWaiting(const std::string& id) {
266     MSStoppingPlace* s = MSNet::getInstance()->getStoppingPlace(id, SUMO_TAG_BUS_STOP);
267     if (s == nullptr) {
268         throw TraCIException("Unknown bus stop '" + id + "'.");
269     }
270     return s->getTransportableNumber();
271 }
272 
273 
274 double
getDeltaT()275 Simulation::getDeltaT() {
276     return TS;
277 }
278 
279 
280 TraCIPositionVector
getNetBoundary()281 Simulation::getNetBoundary() {
282     Boundary b = GeoConvHelper::getFinal().getConvBoundary();
283     TraCIPositionVector tb({ TraCIPosition(), TraCIPosition() });
284     tb[0].x = b.xmin();
285     tb[1].x = b.xmax();
286     tb[0].y = b.ymin();
287     tb[1].y = b.ymax();
288     tb[0].z = b.zmin();
289     tb[1].z = b.zmax();
290     return tb;
291 }
292 
293 
294 int
getMinExpectedNumber()295 Simulation::getMinExpectedNumber() {
296     MSNet* net = MSNet::getInstance();
297     return (net->getVehicleControl().getActiveVehicleCount()
298             + net->getInsertionControl().getPendingFlowCount()
299             + (net->hasPersons() ? net->getPersonControl().getActiveCount() : 0)
300             + (net->hasContainers() ? net->getContainerControl().getActiveCount() : 0));
301 }
302 
303 
304 TraCIPosition
convert2D(const std::string & edgeID,double pos,int laneIndex,bool toGeo)305 Simulation::convert2D(const std::string& edgeID, double pos, int laneIndex, bool toGeo) {
306     Position result = Helper::getLaneChecking(edgeID, laneIndex, pos)->getShape().positionAtOffset(pos);
307     if (toGeo) {
308         GeoConvHelper::getFinal().cartesian2geo(result);
309     }
310     result.setz(0.);
311     return Helper::makeTraCIPosition(result);
312 }
313 
314 
315 TraCIPosition
convert3D(const std::string & edgeID,double pos,int laneIndex,bool toGeo)316 Simulation::convert3D(const std::string& edgeID, double pos, int laneIndex, bool toGeo) {
317     Position result = Helper::getLaneChecking(edgeID, laneIndex, pos)->getShape().positionAtOffset(pos);
318     if (toGeo) {
319         GeoConvHelper::getFinal().cartesian2geo(result);
320     }
321     return Helper::makeTraCIPosition(result, true);
322 }
323 
324 
325 TraCIRoadPosition
convertRoad(double x,double y,bool isGeo,const std::string & vClass)326 Simulation::convertRoad(double x, double y, bool isGeo, const std::string& vClass) {
327     Position pos(x, y);
328     if (isGeo) {
329         GeoConvHelper::getFinal().x2cartesian_const(pos);
330     }
331     if (!SumoVehicleClassStrings.hasString(vClass)) {
332         throw TraCIException("Unknown vehicle class '" + vClass + "'.");
333     }
334     const SUMOVehicleClass vc = SumoVehicleClassStrings.get(vClass);
335     std::pair<MSLane*, double> roadPos = libsumo::Helper::convertCartesianToRoadMap(pos, vc);
336     if (roadPos.first == nullptr) {
337         throw TraCIException("Cannot convert position to road.");
338     }
339     TraCIRoadPosition result;
340     result.edgeID = roadPos.first->getEdge().getID();
341     result.laneIndex = roadPos.first->getIndex();
342     result.pos = roadPos.second;
343     return result;
344 }
345 
346 
347 TraCIPosition
convertGeo(double x,double y,bool fromGeo)348 Simulation::convertGeo(double x, double y, bool fromGeo) {
349     Position pos(x, y);
350     if (fromGeo) {
351         GeoConvHelper::getFinal().x2cartesian_const(pos);
352     } else {
353         GeoConvHelper::getFinal().cartesian2geo(pos);
354     }
355     return Helper::makeTraCIPosition(pos);
356 }
357 
358 
359 double
getDistance2D(double x1,double y1,double x2,double y2,bool isGeo,bool isDriving)360 Simulation::getDistance2D(double x1, double y1, double x2, double y2, bool isGeo, bool isDriving) {
361     Position pos1(x1, y1);
362     Position pos2(x2, y2);
363     if (isGeo) {
364         GeoConvHelper::getFinal().x2cartesian_const(pos1);
365         GeoConvHelper::getFinal().x2cartesian_const(pos2);
366     }
367     if (isDriving) {
368         std::pair<const MSLane*, double> roadPos1 = libsumo::Helper::convertCartesianToRoadMap(pos1, SVC_IGNORING);
369         std::pair<const MSLane*, double> roadPos2 = libsumo::Helper::convertCartesianToRoadMap(pos2, SVC_IGNORING);
370         if ((roadPos1.first == roadPos2.first) && (roadPos1.second <= roadPos2.second)) {
371             // same edge
372             return roadPos2.second - roadPos1.second;
373         } else {
374             double distance = 0.;
375             ConstMSEdgeVector newRoute;
376             if (roadPos2.first->isInternal()) {
377                 distance = roadPos2.second;
378                 roadPos2.first = roadPos2.first->getLogicalPredecessorLane();
379                 roadPos2.second = roadPos2.first->getLength();
380             }
381             MSNet::getInstance()->getRouterTT().compute(
382                 &roadPos1.first->getEdge(), &roadPos2.first->getEdge(), nullptr, MSNet::getInstance()->getCurrentTimeStep(), newRoute);
383             MSRoute route("", newRoute, false, nullptr, std::vector<SUMOVehicleParameter::Stop>());
384             return distance + route.getDistanceBetween(roadPos1.second, roadPos2.second, &roadPos1.first->getEdge(), &roadPos2.first->getEdge());
385         }
386     } else {
387         return pos1.distanceTo(pos2);
388     }
389 }
390 
391 
392 double
getDistanceRoad(const std::string & edgeID1,double pos1,const std::string & edgeID2,double pos2,bool isDriving)393 Simulation::getDistanceRoad(const std::string& edgeID1, double pos1, const std::string& edgeID2, double pos2, bool isDriving) {
394     std::pair<const MSLane*, double> roadPos1 = std::make_pair(libsumo::Helper::getLaneChecking(edgeID1, 0, pos1), pos1);
395     std::pair<const MSLane*, double> roadPos2 = std::make_pair(libsumo::Helper::getLaneChecking(edgeID2, 0, pos2), pos2);
396     if (isDriving) {
397         if ((roadPos1.first == roadPos2.first) && (roadPos1.second <= roadPos2.second)) {
398             // same edge
399             return roadPos2.second - roadPos1.second;
400         } else {
401             double distance = 0.;
402             ConstMSEdgeVector newRoute;
403             if (roadPos2.first->isInternal()) {
404                 distance = roadPos2.second;
405                 roadPos2.first = roadPos2.first->getLogicalPredecessorLane();
406                 roadPos2.second = roadPos2.first->getLength();
407             }
408             MSNet::getInstance()->getRouterTT().compute(
409                 &roadPos1.first->getEdge(), &roadPos2.first->getEdge(), nullptr, MSNet::getInstance()->getCurrentTimeStep(), newRoute);
410             MSRoute route("", newRoute, false, nullptr, std::vector<SUMOVehicleParameter::Stop>());
411             return distance + route.getDistanceBetween(roadPos1.second, roadPos2.second, &roadPos1.first->getEdge(), &roadPos2.first->getEdge());
412         }
413     } else {
414         Position pos1 = roadPos1.first->getShape().positionAtOffset(roadPos1.second);
415         Position pos2 = roadPos2.first->getShape().positionAtOffset(roadPos2.second);
416         return pos1.distanceTo(pos2);
417     }
418 }
419 
420 
421 TraCIStage
findRoute(const std::string & from,const std::string & to,const std::string & typeID,const double depart,const int routingMode)422 Simulation::findRoute(const std::string& from, const std::string& to, const std::string& typeID, const double depart, const int routingMode) {
423     TraCIStage result(MSTransportable::DRIVING);
424     const MSEdge* const fromEdge = MSEdge::dictionary(from);
425     if (fromEdge == nullptr) {
426         throw TraCIException("Unknown from edge '" + from + "'.");
427     }
428     const MSEdge* const toEdge = MSEdge::dictionary(to);
429     if (toEdge == nullptr) {
430         throw TraCIException("Unknown to edge '" + from + "'.");
431     }
432     SUMOVehicle* vehicle = nullptr;
433     if (typeID != "") {
434         SUMOVehicleParameter* pars = new SUMOVehicleParameter();
435         MSVehicleType* type = MSNet::getInstance()->getVehicleControl().getVType(typeID);
436         if (type == nullptr) {
437             throw TraCIException("The vehicle type '" + typeID + "' is not known.");
438         }
439         try {
440             const MSRoute* const routeDummy = new MSRoute("", ConstMSEdgeVector({ fromEdge }), false, nullptr, std::vector<SUMOVehicleParameter::Stop>());
441             vehicle = MSNet::getInstance()->getVehicleControl().buildVehicle(pars, routeDummy, type, false);
442             // we need to fix the speed factor here for deterministic results
443             vehicle->setChosenSpeedFactor(type->getSpeedFactor().getParameter()[0]);
444         } catch (ProcessError& e) {
445             throw TraCIException("Invalid departure edge for vehicle type '" + typeID + "' (" + e.what() + ")");
446         }
447     }
448     ConstMSEdgeVector edges;
449     const SUMOTime dep = depart < 0 ? MSNet::getInstance()->getCurrentTimeStep() : TIME2STEPS(depart);
450     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = routingMode == ROUTING_MODE_AGGREGATED ? MSRoutingEngine::getRouterTT() : MSNet::getInstance()->getRouterTT();
451     router.compute(fromEdge, toEdge, vehicle, dep, edges);
452     for (const MSEdge* e : edges) {
453         result.edges.push_back(e->getID());
454     }
455     result.travelTime = result.cost = router.recomputeCosts(edges, vehicle, dep, &result.length);
456     if (vehicle != nullptr) {
457         MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
458     }
459     return result;
460 }
461 
462 
463 std::vector<TraCIStage>
findIntermodalRoute(const std::string & from,const std::string & to,const std::string & modes,double depart,const int routingMode,double speed,double walkFactor,double departPos,double arrivalPos,const double departPosLat,const std::string & pType,const std::string & vType,const std::string & destStop)464 Simulation::findIntermodalRoute(const std::string& from, const std::string& to,
465                                 const std::string& modes, double depart, const int routingMode, double speed, double walkFactor,
466                                 double departPos, double arrivalPos, const double departPosLat,
467                                 const std::string& pType, const std::string& vType, const std::string& destStop) {
468     UNUSED_PARAMETER(departPosLat);
469     std::vector<TraCIStage> result;
470     const MSEdge* const fromEdge = MSEdge::dictionary(from);
471     if (fromEdge == nullptr) {
472         throw TraCIException("Unknown from edge '" + from + "'.");
473     }
474     const MSEdge* const toEdge = MSEdge::dictionary(to);
475     if (toEdge == nullptr) {
476         throw TraCIException("Unknown to edge '" + to + "'.");
477     }
478     MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
479     SVCPermissions modeSet = 0;
480     std::vector<SUMOVehicleParameter*> pars;
481     if (vType != "") {
482         pars.push_back(new SUMOVehicleParameter());
483         pars.back()->vtypeid = vType;
484         pars.back()->id = vType;
485         modeSet |= SVC_PASSENGER;
486     }
487     for (StringTokenizer st(modes); st.hasNext();) {
488         const std::string mode = st.next();
489         if (mode == toString(PERSONMODE_CAR)) {
490             pars.push_back(new SUMOVehicleParameter());
491             pars.back()->vtypeid = DEFAULT_VTYPE_ID;
492             pars.back()->id = mode;
493             modeSet |= SVC_PASSENGER;
494         } else if (mode == toString(PERSONMODE_BICYCLE)) {
495             pars.push_back(new SUMOVehicleParameter());
496             pars.back()->vtypeid = DEFAULT_BIKETYPE_ID;
497             pars.back()->id = mode;
498             modeSet |= SVC_BICYCLE;
499         } else if (mode == toString(PERSONMODE_PUBLIC)) {
500             pars.push_back(nullptr);
501             modeSet |= SVC_BUS;
502         } else if (mode == toString(PERSONMODE_WALK)) {
503             // do nothing
504         } else {
505             throw TraCIException("Unknown person mode '" + mode + "'.");
506         }
507     }
508     if (pars.empty()) {
509         pars.push_back(nullptr);
510     }
511     // interpret default arguments
512     const MSVehicleType* pedType = vehControl.hasVType(pType) ? vehControl.getVType(pType) : vehControl.getVType(DEFAULT_PEDTYPE_ID);
513     SUMOTime departStep = TIME2STEPS(depart);
514     if (depart < 0) {
515         departStep = MSNet::getInstance()->getCurrentTimeStep();
516     }
517     if (speed < 0) {
518         speed =  pedType->getMaxSpeed();
519     }
520     if (walkFactor < 0) {
521         walkFactor = OptionsCont::getOptions().getFloat("persontrip.walkfactor");
522     }
523     const double externalFactor = StringUtils::toDouble(pedType->getParameter().getParameter("externalEffortFactor", "100"));
524     if (departPos < 0) {
525         departPos += fromEdge->getLength();
526     }
527     if (arrivalPos == INVALID_DOUBLE_VALUE) {
528         arrivalPos = toEdge->getLength() / 2;
529     } else if (arrivalPos < 0) {
530         arrivalPos += toEdge->getLength();
531     }
532     if (departPos < 0 || departPos >= fromEdge->getLength()) {
533         throw TraCIException("Invalid depart position " + toString(departPos) + " for edge '" + to + "'.");
534     }
535     if (arrivalPos < 0 || arrivalPos >= toEdge->getLength()) {
536         throw TraCIException("Invalid arrival position " + toString(arrivalPos) + " for edge '" + to + "'.");
537     }
538     double minCost = std::numeric_limits<double>::max();
539     MSNet::MSIntermodalRouter& router = MSNet::getInstance()->getIntermodalRouter(routingMode);
540     for (SUMOVehicleParameter* vehPar : pars) {
541         std::vector<TraCIStage> resultCand;
542         SUMOVehicle* vehicle = nullptr;
543         if (vehPar != nullptr) {
544             MSVehicleType* type = MSNet::getInstance()->getVehicleControl().getVType(vehPar->vtypeid);
545             if (type == nullptr) {
546                 throw TraCIException("Unknown vehicle type '" + vehPar->vtypeid + "'.");
547             }
548             if (type->getVehicleClass() != SVC_IGNORING && (fromEdge->getPermissions() & type->getVehicleClass()) == 0) {
549                 WRITE_WARNING("Ignoring vehicle type '" + type->getID() + "' when performing intermodal routing because it is not allowed on the start edge '" + from + "'.");
550             } else {
551                 const MSRoute* const routeDummy = new MSRoute(vehPar->id, ConstMSEdgeVector({ fromEdge }), false, nullptr, std::vector<SUMOVehicleParameter::Stop>());
552                 vehicle = vehControl.buildVehicle(vehPar, routeDummy, type, !MSGlobals::gCheckRoutes);
553                 // we need to fix the speed factor here for deterministic results
554                 vehicle->setChosenSpeedFactor(type->getSpeedFactor().getParameter()[0]);
555             }
556         }
557         std::vector<MSNet::MSIntermodalRouter::TripItem> items;
558         if (router.compute(fromEdge, toEdge, departPos, arrivalPos, destStop,
559                            speed * walkFactor, vehicle, modeSet, departStep, items, externalFactor)) {
560             double cost = 0;
561             for (std::vector<MSNet::MSIntermodalRouter::TripItem>::iterator it = items.begin(); it != items.end(); ++it) {
562                 if (!it->edges.empty()) {
563                     resultCand.push_back(TraCIStage(it->line == ""
564                                                     ? MSTransportable::MOVING_WITHOUT_VEHICLE
565                                                     : MSTransportable::DRIVING));
566                     resultCand.back().vType = it->vType;
567                     resultCand.back().line = it->line;
568                     resultCand.back().destStop = it->destStop;
569                     for (const MSEdge* e : it->edges) {
570                         resultCand.back().edges.push_back(e->getID());
571                     }
572                     resultCand.back().travelTime = it->traveltime;
573                     resultCand.back().cost = it->cost;
574                     resultCand.back().length = it->length;
575                     resultCand.back().intended = it->intended;
576                     resultCand.back().depart = it->depart;
577                     resultCand.back().departPos = it->departPos;
578                     resultCand.back().arrivalPos = it->arrivalPos;
579                     resultCand.back().description = it->description;
580                 }
581                 cost += it->cost;
582             }
583             if (cost < minCost) {
584                 minCost = cost;
585                 result = resultCand;
586             }
587         }
588         if (vehicle != nullptr) {
589             vehControl.deleteVehicle(vehicle, true);
590         }
591     }
592     return result;
593 }
594 
595 
596 std::string
getParameter(const std::string & objectID,const std::string & key)597 Simulation::getParameter(const std::string& objectID, const std::string& key) {
598     if (StringUtils::startsWith(key, "chargingStation.")) {
599         const std::string attrName = key.substr(16);
600         MSChargingStation* cs = static_cast<MSChargingStation*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_CHARGING_STATION));
601         if (cs == nullptr) {
602             throw TraCIException("Invalid chargingStation '" + objectID + "'");
603         }
604         if (attrName == toString(SUMO_ATTR_TOTALENERGYCHARGED)) {
605             return toString(cs->getTotalCharged());
606         } else if (attrName == toString(SUMO_ATTR_NAME)) {
607             return toString(cs->getMyName());
608         } else {
609             throw TraCIException("Invalid chargingStation parameter '" + attrName + "'");
610         }
611     } else if (StringUtils::startsWith(key, "parkingArea.")) {
612         const std::string attrName = key.substr(12);
613         MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_PARKING_AREA));
614         if (pa == nullptr) {
615             throw TraCIException("Invalid parkingArea '" + objectID + "'");
616         }
617         if (attrName == "capacity") {
618             return toString(pa->getCapacity());
619         } else if (attrName == "occupancy") {
620             return toString(pa->getOccupancy());
621         } else if (attrName == toString(SUMO_ATTR_NAME)) {
622             return toString(pa->getMyName());
623         } else {
624             throw TraCIException("Invalid parkingArea parameter '" + attrName + "'");
625         }
626     } else if (StringUtils::startsWith(key, "busStop.")) {
627         const std::string attrName = key.substr(8);
628         MSStoppingPlace* bs = static_cast<MSStoppingPlace*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_BUS_STOP));
629         if (bs == nullptr) {
630             throw TraCIException("Invalid busStop '" + objectID + "'");
631         }
632         if (attrName == toString(SUMO_ATTR_NAME)) {
633             return toString(bs->getMyName());
634         } else {
635             throw TraCIException("Invalid busStop parameter '" + attrName + "'");
636         }
637     } else {
638         throw TraCIException("Parameter '" + key + "' is not supported.");
639     }
640 }
641 
642 
643 void
clearPending(const std::string & routeID)644 Simulation::clearPending(const std::string& routeID) {
645     MSNet::getInstance()->getInsertionControl().clearPendingVehicles(routeID);
646 }
647 
648 
649 void
saveState(const std::string & fileName)650 Simulation::saveState(const std::string& fileName) {
651     MSStateHandler::saveState(fileName, MSNet::getInstance()->getCurrentTimeStep());
652 }
653 
654 
655 std::shared_ptr<VariableWrapper>
makeWrapper()656 Simulation::makeWrapper() {
657     return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
658 }
659 
660 
661 bool
handleVariable(const std::string & objID,const int variable,VariableWrapper * wrapper)662 Simulation::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper) {
663     switch (variable) {
664         case VAR_TIME:
665             return wrapper->wrapDouble(objID, variable, getTime());
666         case VAR_TIME_STEP:
667             return wrapper->wrapInt(objID, variable, (int)getCurrentTime());
668         case VAR_LOADED_VEHICLES_NUMBER:
669             return wrapper->wrapInt(objID, variable, getLoadedNumber());
670         case VAR_LOADED_VEHICLES_IDS:
671             return wrapper->wrapStringList(objID, variable, getLoadedIDList());
672         case VAR_DEPARTED_VEHICLES_NUMBER:
673             return wrapper->wrapInt(objID, variable, getDepartedNumber());
674         case VAR_DEPARTED_VEHICLES_IDS:
675             return wrapper->wrapStringList(objID, variable, getDepartedIDList());
676         case VAR_TELEPORT_STARTING_VEHICLES_NUMBER:
677             return wrapper->wrapInt(objID, variable, getStartingTeleportNumber());
678         case VAR_TELEPORT_STARTING_VEHICLES_IDS:
679             return wrapper->wrapStringList(objID, variable, getStartingTeleportIDList());
680         case VAR_TELEPORT_ENDING_VEHICLES_NUMBER:
681             return wrapper->wrapInt(objID, variable, getEndingTeleportNumber());
682         case VAR_TELEPORT_ENDING_VEHICLES_IDS:
683             return wrapper->wrapStringList(objID, variable, getEndingTeleportIDList());
684         case VAR_ARRIVED_VEHICLES_NUMBER:
685             return wrapper->wrapInt(objID, variable, getArrivedNumber());
686         case VAR_ARRIVED_VEHICLES_IDS:
687             return wrapper->wrapStringList(objID, variable, getArrivedIDList());
688         case VAR_PARKING_STARTING_VEHICLES_NUMBER:
689             return wrapper->wrapInt(objID, variable, getParkingStartingVehiclesNumber());
690         case VAR_PARKING_STARTING_VEHICLES_IDS:
691             return wrapper->wrapStringList(objID, variable, getParkingStartingVehiclesIDList());
692         case VAR_PARKING_ENDING_VEHICLES_NUMBER:
693             return wrapper->wrapInt(objID, variable, getParkingEndingVehiclesNumber());
694         case VAR_PARKING_ENDING_VEHICLES_IDS:
695             return wrapper->wrapStringList(objID, variable, getParkingEndingVehiclesIDList());
696         case VAR_STOP_STARTING_VEHICLES_NUMBER:
697             return wrapper->wrapInt(objID, variable, getStopStartingVehiclesNumber());
698         case VAR_STOP_STARTING_VEHICLES_IDS:
699             return wrapper->wrapStringList(objID, variable, getStopStartingVehiclesIDList());
700         case VAR_STOP_ENDING_VEHICLES_NUMBER:
701             return wrapper->wrapInt(objID, variable, getStopEndingVehiclesNumber());
702         case VAR_STOP_ENDING_VEHICLES_IDS:
703             return wrapper->wrapStringList(objID, variable, getStopEndingVehiclesIDList());
704         case VAR_COLLIDING_VEHICLES_NUMBER:
705             return wrapper->wrapInt(objID, variable, getCollidingVehiclesNumber());
706         case VAR_COLLIDING_VEHICLES_IDS:
707             return wrapper->wrapStringList(objID, variable, getCollidingVehiclesIDList());
708         case VAR_EMERGENCYSTOPPING_VEHICLES_NUMBER:
709             return wrapper->wrapInt(objID, variable, getEmergencyStoppingVehiclesNumber());
710         case VAR_EMERGENCYSTOPPING_VEHICLES_IDS:
711             return wrapper->wrapStringList(objID, variable, getEmergencyStoppingVehiclesIDList());
712         case VAR_DELTA_T:
713             return wrapper->wrapDouble(objID, variable, getDeltaT());
714         case VAR_MIN_EXPECTED_VEHICLES:
715             return wrapper->wrapInt(objID, variable, getMinExpectedNumber());
716         case VAR_BUS_STOP_WAITING:
717             return wrapper->wrapInt(objID, variable, getBusStopWaiting(objID));
718         default:
719             return false;
720     }
721 }
722 
723 
724 }
725 
726 
727 /****************************************************************************/
728