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