Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/libsumo/Simulation.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2017-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 Simulation.cpp
15
/// @author Laura Bieker-Walz
16
/// @author Robert Hilbrich
17
/// @author Mirko Barthauer
18
/// @date 15.09.2017
19
///
20
// C++ TraCI client API implementation
21
/****************************************************************************/
22
#include <config.h>
23
#ifdef HAVE_VERSION_H
24
#include <version.h>
25
#endif
26
#include <utils/options/OptionsCont.h>
27
#include <utils/common/MsgHandler.h>
28
#include <utils/common/StdDefs.h>
29
#include <utils/common/StringTokenizer.h>
30
#include <utils/common/StringUtils.h>
31
#include <utils/common/SystemFrame.h>
32
#include <utils/geom/GeoConvHelper.h>
33
#include <utils/options/OptionsIO.h>
34
#include <utils/router/IntermodalRouter.h>
35
#include <utils/router/PedestrianRouter.h>
36
#include <utils/xml/XMLSubSys.h>
37
#include <microsim/MSNet.h>
38
#include <microsim/MSEdgeControl.h>
39
#include <microsim/MSInsertionControl.h>
40
#include <microsim/MSEdge.h>
41
#include <microsim/MSLane.h>
42
#include <microsim/MSVehicle.h>
43
#include <microsim/MSVehicleControl.h>
44
#include <microsim/MSVehicleTransfer.h>
45
#include <microsim/transportables/MSTransportableControl.h>
46
#include <microsim/MSStateHandler.h>
47
#include <microsim/MSStoppingPlace.h>
48
#include <microsim/MSParkingArea.h>
49
#include <microsim/devices/MSRoutingEngine.h>
50
#include <microsim/devices/MSDevice_Taxi.h>
51
#include <microsim/trigger/MSChargingStation.h>
52
#include <microsim/trigger/MSOverheadWire.h>
53
#include <microsim/devices/MSDevice_Tripinfo.h>
54
#include <mesosim/MELoop.h>
55
#include <mesosim/MESegment.h>
56
#include <netload/NLBuilder.h>
57
#include <libsumo/Helper.h>
58
#include <libsumo/StorageHelper.h>
59
#include <libsumo/TraCIConstants.h>
60
#ifdef HAVE_LIBSUMOGUI
61
#include "GUI.h"
62
#endif
63
#include "Simulation.h"
64
#include <libsumo/TraCIDefs.h>
65
66
67
namespace libsumo {
68
// ===========================================================================
69
// static member initializations
70
// ===========================================================================
71
SubscriptionResults Simulation::mySubscriptionResults;
72
ContextSubscriptionResults Simulation::myContextSubscriptionResults;
73
#ifdef HAVE_FOX
74
FXMutex Simulation::myStepMutex;
75
#endif
76
77
78
// ===========================================================================
79
// static member definitions
80
// ===========================================================================
81
std::pair<int, std::string>
82
Simulation::init(int /* port */, int /* numRetries */, const std::string& /* host */, const std::string& /* label */, FILE* const /* pipe */) {
83
throw TraCIException("Multi client support (including connection switching) is not implemented in libsumo.");
84
}
85
86
87
std::pair<int, std::string>
88
Simulation::start(const std::vector<std::string>& cmd, int /* port */, int /* numRetries */, const std::string& /* label */, const bool /* verbose */,
89
const std::string& /* traceFile */, bool /* traceGetters */, void* /* _stdout */) {
90
#ifdef HAVE_LIBSUMOGUI
91
if (GUI::start(cmd)) {
92
return getVersion();
93
}
94
#endif
95
load(std::vector<std::string>(cmd.begin() + 1, cmd.end()));
96
return getVersion();
97
}
98
99
100
bool
101
Simulation::isLibsumo() {
102
return true;
103
}
104
105
106
void
107
Simulation::switchConnection(const std::string& /* label */) {
108
throw TraCIException("Multi client support (including connection switching) is not implemented in libsumo.");
109
}
110
111
112
const std::string&
113
Simulation::getLabel() {
114
throw TraCIException("Multi client support (including connection switching) is not implemented in libsumo.");
115
}
116
117
118
void
119
Simulation::setOrder(int /* order */) {
120
throw TraCIException("Multi client support (including connection switching) is not implemented in libsumo.");
121
}
122
123
124
void
125
Simulation::load(const std::vector<std::string>& args) {
126
#ifdef HAVE_LIBSUMOGUI
127
if (GUI::load(args)) {
128
return;
129
}
130
#endif
131
close("Libsumo issued load command.");
132
try {
133
OptionsCont::getOptions().setApplicationName("libsumo", "Eclipse SUMO libsumo " VERSION_STRING);
134
gSimulation = true;
135
XMLSubSys::init();
136
OptionsIO::setArgs(args);
137
if (NLBuilder::init(true) != nullptr) {
138
const SUMOTime begin = string2time(OptionsCont::getOptions().getString("begin"));
139
MSNet::getInstance()->setCurrentTimeStep(begin); // needed for state loading
140
WRITE_MESSAGEF(TL("Simulation version % started via libsumo with time: %."), VERSION_STRING, time2string(begin));
141
}
142
} catch (ProcessError& e) {
143
throw TraCIException(e.what());
144
}
145
}
146
147
148
bool
149
Simulation::hasGUI() {
150
#ifdef HAVE_LIBSUMOGUI
151
return GUI::hasInstance();
152
#else
153
return false;
154
#endif
155
}
156
157
158
bool
159
Simulation::isLoaded() {
160
return MSNet::hasInstance();
161
}
162
163
164
void
165
Simulation::step(const double time) {
166
#ifdef HAVE_FOX
167
FXMutexLock lock(myStepMutex);
168
#endif
169
Helper::clearStateChanges();
170
const SUMOTime t = TIME2STEPS(time);
171
#ifdef HAVE_LIBSUMOGUI
172
if (!GUI::step(t)) {
173
#endif
174
if (t == 0) {
175
MSNet::getInstance()->simulationStep();
176
} else {
177
while (SIMSTEP < t) {
178
MSNet::getInstance()->simulationStep();
179
}
180
}
181
#ifdef HAVE_LIBSUMOGUI
182
}
183
#endif
184
Helper::handleSubscriptions(SIMSTEP);
185
}
186
187
188
void
189
Simulation::executeMove() {
190
MSNet::getInstance()->simulationStep(true);
191
}
192
193
194
void
195
Simulation::close(const std::string& reason) {
196
Helper::clearSubscriptions();
197
if (
198
#ifdef HAVE_LIBSUMOGUI
199
!GUI::close(reason) &&
200
#endif
201
MSNet::hasInstance()) {
202
MSNet::getInstance()->closeSimulation(0, reason);
203
delete MSNet::getInstance();
204
SystemFrame::close();
205
}
206
}
207
208
209
void
210
Simulation::subscribe(const std::vector<int>& varIDs, double begin, double end, const libsumo::TraCIResults& parameters) {
211
libsumo::Helper::subscribe(CMD_SUBSCRIBE_SIM_VARIABLE, "", varIDs, begin, end, parameters);
212
}
213
214
215
const TraCIResults
216
Simulation::getSubscriptionResults() {
217
return mySubscriptionResults[""];
218
}
219
220
221
LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Simulation, SIM)
222
223
224
std::pair<int, std::string>
225
Simulation::getVersion() {
226
return std::make_pair(libsumo::TRACI_VERSION, "SUMO " VERSION_STRING);
227
}
228
229
230
std::string
231
Simulation::getOption(const std::string& option) {
232
OptionsCont& oc = OptionsCont::getOptions();
233
if (!oc.exists(option)) {
234
throw TraCIException("The option " + option + " is unknown.");
235
}
236
return oc.getValueString(option);
237
}
238
239
240
int
241
Simulation::getCurrentTime() {
242
return (int)MSNet::getInstance()->getCurrentTimeStep();
243
}
244
245
246
double
247
Simulation::getTime() {
248
return SIMTIME;
249
}
250
251
double
252
Simulation::getEndTime() {
253
return STEPS2TIME(string2time(OptionsCont::getOptions().getString("end")));
254
}
255
256
257
int
258
Simulation::getLoadedNumber() {
259
return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::BUILT).size();
260
}
261
262
263
std::vector<std::string>
264
Simulation::getLoadedIDList() {
265
return Helper::getVehicleStateChanges(MSNet::VehicleState::BUILT);
266
}
267
268
269
int
270
Simulation::getDepartedNumber() {
271
return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::DEPARTED).size();
272
}
273
274
275
std::vector<std::string>
276
Simulation::getDepartedIDList() {
277
return Helper::getVehicleStateChanges(MSNet::VehicleState::DEPARTED);
278
}
279
280
281
int
282
Simulation::getArrivedNumber() {
283
return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::ARRIVED).size();
284
}
285
286
287
std::vector<std::string>
288
Simulation::getArrivedIDList() {
289
return Helper::getVehicleStateChanges(MSNet::VehicleState::ARRIVED);
290
}
291
292
293
int
294
Simulation::getParkingStartingVehiclesNumber() {
295
return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_PARKING).size();
296
}
297
298
299
std::vector<std::string>
300
Simulation::getParkingStartingVehiclesIDList() {
301
return Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_PARKING);
302
}
303
304
305
int
306
Simulation::getParkingEndingVehiclesNumber() {
307
return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_PARKING).size();
308
}
309
310
311
std::vector<std::string>
312
Simulation::getParkingEndingVehiclesIDList() {
313
return Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_PARKING);
314
}
315
316
317
int
318
Simulation::getStopStartingVehiclesNumber() {
319
return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_STOP).size();
320
}
321
322
323
std::vector<std::string>
324
Simulation::getStopStartingVehiclesIDList() {
325
return Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_STOP);
326
}
327
328
329
int
330
Simulation::getStopEndingVehiclesNumber() {
331
return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_STOP).size();
332
}
333
334
335
std::vector<std::string>
336
Simulation::getStopEndingVehiclesIDList() {
337
return Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_STOP);
338
}
339
340
341
int
342
Simulation::getCollidingVehiclesNumber() {
343
return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::COLLISION).size();
344
}
345
346
347
std::vector<std::string>
348
Simulation::getCollidingVehiclesIDList() {
349
return Helper::getVehicleStateChanges(MSNet::VehicleState::COLLISION);
350
}
351
352
353
int
354
Simulation::getEmergencyStoppingVehiclesNumber() {
355
return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::EMERGENCYSTOP).size();
356
}
357
358
359
std::vector<std::string>
360
Simulation::getEmergencyStoppingVehiclesIDList() {
361
return Helper::getVehicleStateChanges(MSNet::VehicleState::EMERGENCYSTOP);
362
}
363
364
365
int
366
Simulation::getStartingTeleportNumber() {
367
return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_TELEPORT).size();
368
}
369
370
371
std::vector<std::string>
372
Simulation::getStartingTeleportIDList() {
373
return Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_TELEPORT);
374
}
375
376
377
int
378
Simulation::getEndingTeleportNumber() {
379
return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_TELEPORT).size();
380
}
381
382
383
std::vector<std::string>
384
Simulation::getEndingTeleportIDList() {
385
return Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_TELEPORT);
386
}
387
388
int
389
Simulation::getDepartedPersonNumber() {
390
return (int)Helper::getTransportableStateChanges(MSNet::TransportableState::PERSON_DEPARTED).size();
391
}
392
393
394
std::vector<std::string>
395
Simulation::getDepartedPersonIDList() {
396
return Helper::getTransportableStateChanges(MSNet::TransportableState::PERSON_DEPARTED);
397
}
398
399
400
int
401
Simulation::getArrivedPersonNumber() {
402
return (int)Helper::getTransportableStateChanges(MSNet::TransportableState::PERSON_ARRIVED).size();
403
}
404
405
406
std::vector<std::string>
407
Simulation::getArrivedPersonIDList() {
408
return Helper::getTransportableStateChanges(MSNet::TransportableState::PERSON_ARRIVED);
409
}
410
411
std::vector<std::string>
412
Simulation::getBusStopIDList() {
413
std::vector<std::string> result;
414
for (const auto& pair : MSNet::getInstance()->getStoppingPlaces(SUMO_TAG_BUS_STOP)) {
415
result.push_back(pair.first);
416
}
417
return result;
418
}
419
420
int
421
Simulation::getBusStopWaiting(const std::string& stopID) {
422
MSStoppingPlace* s = MSNet::getInstance()->getStoppingPlace(stopID, SUMO_TAG_BUS_STOP);
423
if (s == nullptr) {
424
throw TraCIException("Unknown bus stop '" + stopID + "'.");
425
}
426
return s->getTransportableNumber();
427
}
428
429
std::vector<std::string>
430
Simulation::getBusStopWaitingIDList(const std::string& stopID) {
431
MSStoppingPlace* s = MSNet::getInstance()->getStoppingPlace(stopID, SUMO_TAG_BUS_STOP);
432
if (s == nullptr) {
433
throw TraCIException("Unknown bus stop '" + stopID + "'.");
434
}
435
std::vector<std::string> result;
436
for (const MSTransportable* t : s->getTransportables()) {
437
result.push_back(t->getID());
438
}
439
return result;
440
}
441
442
443
std::vector<std::string>
444
Simulation::getPendingVehicles() {
445
std::vector<std::string> result;
446
for (const SUMOVehicle* veh : MSNet::getInstance()->getInsertionControl().getPendingVehicles()) {
447
result.push_back(veh->getID());
448
}
449
return result;
450
}
451
452
453
std::vector<libsumo::TraCICollision>
454
Simulation::getCollisions() {
455
std::vector<libsumo::TraCICollision> result;
456
for (auto item : MSNet::getInstance()->getCollisions()) {
457
for (const MSNet::Collision& c : item.second) {
458
libsumo::TraCICollision c2;
459
c2.collider = item.first;
460
c2.victim = c.victim;
461
c2.colliderType = c.colliderType;
462
c2.victimType = c.victimType;
463
c2.colliderSpeed = c.colliderSpeed;
464
c2.victimSpeed = c.victimSpeed;
465
c2.type = c.type;
466
c2.lane = c.lane->getID();
467
c2.pos = c.pos;
468
result.push_back(c2);
469
}
470
}
471
return result;
472
}
473
474
double
475
Simulation::getScale() {
476
return MSNet::getInstance()->getVehicleControl().getScale();
477
}
478
479
double
480
Simulation::getDeltaT() {
481
return TS;
482
}
483
484
485
TraCIPositionVector
486
Simulation::getNetBoundary() {
487
Boundary b = GeoConvHelper::getFinal().getConvBoundary();
488
TraCIPositionVector tb;
489
TraCIPosition minV;
490
TraCIPosition maxV;
491
minV.x = b.xmin();
492
maxV.x = b.xmax();
493
minV.y = b.ymin();
494
maxV.y = b.ymax();
495
minV.z = b.zmin();
496
maxV.z = b.zmax();
497
tb.value.push_back(minV);
498
tb.value.push_back(maxV);
499
return tb;
500
}
501
502
503
int
504
Simulation::getMinExpectedNumber() {
505
MSNet* net = MSNet::getInstance();
506
return (net->getVehicleControl().getActiveVehicleCount()
507
+ net->getInsertionControl().getPendingFlowCount()
508
+ (net->hasPersons() ? net->getPersonControl().getActiveCount() : 0)
509
+ (net->hasContainers() ? net->getContainerControl().getActiveCount() : 0)
510
+ (MSDevice_Taxi::hasServableReservations() ? 1 : 0));
511
}
512
513
514
TraCIPosition
515
Simulation::convert2D(const std::string& edgeID, double pos, int laneIndex, bool toGeo) {
516
Position result = Helper::getLaneChecking(edgeID, laneIndex, pos)->geometryPositionAtOffset(pos);
517
if (toGeo) {
518
GeoConvHelper::getFinal().cartesian2geo(result);
519
}
520
result.setz(0.);
521
return Helper::makeTraCIPosition(result);
522
}
523
524
525
TraCIPosition
526
Simulation::convert3D(const std::string& edgeID, double pos, int laneIndex, bool toGeo) {
527
Position result = Helper::getLaneChecking(edgeID, laneIndex, pos)->geometryPositionAtOffset(pos);
528
if (toGeo) {
529
GeoConvHelper::getFinal().cartesian2geo(result);
530
}
531
return Helper::makeTraCIPosition(result, true);
532
}
533
534
535
TraCIRoadPosition
536
Simulation::convertRoad(double x, double y, bool isGeo, const std::string& vClass) {
537
Position pos(x, y);
538
if (isGeo) {
539
GeoConvHelper::getFinal().x2cartesian_const(pos);
540
}
541
if (!SumoVehicleClassStrings.hasString(vClass)) {
542
throw TraCIException("Unknown vehicle class '" + vClass + "'.");
543
}
544
const SUMOVehicleClass vc = SumoVehicleClassStrings.get(vClass);
545
std::pair<MSLane*, double> roadPos = libsumo::Helper::convertCartesianToRoadMap(pos, vc);
546
if (roadPos.first == nullptr) {
547
throw TraCIException("Cannot convert position to road.");
548
}
549
TraCIRoadPosition result;
550
result.edgeID = roadPos.first->getEdge().getID();
551
result.laneIndex = roadPos.first->getIndex();
552
result.pos = roadPos.second;
553
return result;
554
}
555
556
557
TraCIPosition
558
Simulation::convertGeo(double x, double y, bool fromGeo) {
559
Position pos(x, y);
560
if (fromGeo) {
561
GeoConvHelper::getFinal().x2cartesian_const(pos);
562
} else {
563
GeoConvHelper::getFinal().cartesian2geo(pos);
564
}
565
return Helper::makeTraCIPosition(pos);
566
}
567
568
569
double
570
Simulation::getDistance2D(double x1, double y1, double x2, double y2, bool isGeo, bool isDriving) {
571
Position pos1(x1, y1);
572
Position pos2(x2, y2);
573
if (isGeo) {
574
GeoConvHelper::getFinal().x2cartesian_const(pos1);
575
GeoConvHelper::getFinal().x2cartesian_const(pos2);
576
}
577
if (isDriving) {
578
std::pair<const MSLane*, double> roadPos1 = libsumo::Helper::convertCartesianToRoadMap(pos1, SVC_IGNORING);
579
std::pair<const MSLane*, double> roadPos2 = libsumo::Helper::convertCartesianToRoadMap(pos2, SVC_IGNORING);
580
return Helper::getDrivingDistance(roadPos1, roadPos2);
581
} else {
582
return pos1.distanceTo(pos2);
583
}
584
}
585
586
587
double
588
Simulation::getDistanceRoad(const std::string& edgeID1, double pos1, const std::string& edgeID2, double pos2, bool isDriving) {
589
std::pair<const MSLane*, double> roadPos1 = std::make_pair(libsumo::Helper::getLaneChecking(edgeID1, 0, pos1), pos1);
590
std::pair<const MSLane*, double> roadPos2 = std::make_pair(libsumo::Helper::getLaneChecking(edgeID2, 0, pos2), pos2);
591
if (isDriving) {
592
return Helper::getDrivingDistance(roadPos1, roadPos2);
593
} else {
594
const Position p1 = roadPos1.first->geometryPositionAtOffset(roadPos1.second);
595
const Position p2 = roadPos2.first->geometryPositionAtOffset(roadPos2.second);
596
return p1.distanceTo(p2);
597
}
598
}
599
600
601
TraCIStage
602
Simulation::findRoute(const std::string& from, const std::string& to, const std::string& typeID, const double depart, const int routingMode) {
603
TraCIStage result(STAGE_DRIVING);
604
const MSEdge* const fromEdge = MSEdge::dictionary(from);
605
if (fromEdge == nullptr) {
606
throw TraCIException("Unknown from edge '" + from + "'.");
607
}
608
const MSEdge* const toEdge = MSEdge::dictionary(to);
609
if (toEdge == nullptr) {
610
throw TraCIException("Unknown to edge '" + to + "'.");
611
}
612
MSBaseVehicle* vehicle = nullptr;
613
MSVehicleType* type = MSNet::getInstance()->getVehicleControl().getVType(typeID == "" ? DEFAULT_VTYPE_ID : typeID);
614
if (type == nullptr) {
615
throw TraCIException("The vehicle type '" + typeID + "' is not known.");
616
}
617
SUMOVehicleParameter* pars = new SUMOVehicleParameter();
618
pars->id = "simulation.findRoute";
619
try {
620
ConstMSRoutePtr const routeDummy = std::make_shared<MSRoute>("", ConstMSEdgeVector({ fromEdge }), false, nullptr, StopParVector());
621
vehicle = dynamic_cast<MSBaseVehicle*>(MSNet::getInstance()->getVehicleControl().buildVehicle(pars, routeDummy, type, false));
622
std::string msg;
623
if (!vehicle->hasValidRouteStart(msg)) {
624
MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
625
MSNet::getInstance()->getVehicleControl().discountRoutingVehicle();
626
throw TraCIException("Invalid departure edge for vehicle type '" + type->getID() + "' (" + msg + ")");
627
}
628
// we need to fix the speed factor here for deterministic results
629
vehicle->setChosenSpeedFactor(type->getSpeedFactor().getParameter(0));
630
vehicle->setRoutingMode(routingMode);
631
} catch (ProcessError& e) {
632
throw TraCIException("Invalid departure edge for vehicle type '" + type->getID() + "' (" + e.what() + ")");
633
}
634
ConstMSEdgeVector edges;
635
const SUMOTime dep = depart < 0 ? MSNet::getInstance()->getCurrentTimeStep() : TIME2STEPS(depart);
636
SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = routingMode == ROUTING_MODE_AGGREGATED ? MSRoutingEngine::getRouterTT(0, vehicle->getVClass()) : MSNet::getInstance()->getRouterTT(0);
637
router.compute(fromEdge, toEdge, vehicle, dep, edges);
638
for (const MSEdge* e : edges) {
639
result.edges.push_back(e->getID());
640
}
641
result.travelTime = result.cost = router.recomputeCosts(edges, vehicle, dep, &result.length);
642
if (vehicle != nullptr) {
643
MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
644
MSNet::getInstance()->getVehicleControl().discountRoutingVehicle();
645
}
646
return result;
647
}
648
649
650
std::vector<TraCIStage>
651
Simulation::findIntermodalRoute(const std::string& from, const std::string& to,
652
const std::string& modes, double depart, const int routingMode, double speed, double walkFactor,
653
double departPos, double arrivalPos, const double departPosLat,
654
const std::string& pType, const std::string& vType, const std::string& destStop) {
655
UNUSED_PARAMETER(departPosLat);
656
std::vector<TraCIStage> result;
657
const MSEdge* const fromEdge = MSEdge::dictionary(from);
658
if (fromEdge == nullptr) {
659
throw TraCIException("Unknown from edge '" + from + "'.");
660
}
661
const MSEdge* const toEdge = MSEdge::dictionary(to);
662
if (toEdge == nullptr) {
663
throw TraCIException("Unknown to edge '" + to + "'.");
664
}
665
MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
666
SVCPermissions modeSet = 0;
667
std::vector<SUMOVehicleParameter*> pars;
668
if (vType != "") {
669
pars.push_back(new SUMOVehicleParameter());
670
pars.back()->vtypeid = vType;
671
pars.back()->id = vType;
672
modeSet |= SVC_PASSENGER;
673
}
674
for (StringTokenizer st(modes); st.hasNext();) {
675
const std::string mode = st.next();
676
if (mode == toString(PersonMode::CAR)) {
677
pars.push_back(new SUMOVehicleParameter());
678
pars.back()->vtypeid = DEFAULT_VTYPE_ID;
679
pars.back()->id = mode;
680
modeSet |= SVC_PASSENGER;
681
} else if (mode == toString(PersonMode::BICYCLE)) {
682
pars.push_back(new SUMOVehicleParameter());
683
pars.back()->vtypeid = DEFAULT_BIKETYPE_ID;
684
pars.back()->id = mode;
685
modeSet |= SVC_BICYCLE;
686
} else if (mode == toString(PersonMode::TAXI)) {
687
pars.push_back(new SUMOVehicleParameter());
688
pars.back()->vtypeid = DEFAULT_TAXITYPE_ID;
689
pars.back()->id = mode;
690
pars.back()->line = mode;
691
modeSet |= SVC_TAXI;
692
} else if (mode == toString(PersonMode::PUBLIC)) {
693
pars.push_back(nullptr);
694
modeSet |= SVC_BUS;
695
} else if (mode == toString(PersonMode::WALK)) {
696
// do nothing
697
} else {
698
throw TraCIException("Unknown person mode '" + mode + "'.");
699
}
700
}
701
if (pars.empty()) {
702
pars.push_back(nullptr);
703
}
704
// interpret default arguments
705
const MSVehicleType* pedType = vehControl.hasVType(pType) ? vehControl.getVType(pType) : vehControl.getVType(DEFAULT_PEDTYPE_ID);
706
SUMOTime departStep = TIME2STEPS(depart);
707
if (depart < 0) {
708
departStep = MSNet::getInstance()->getCurrentTimeStep();
709
}
710
if (speed < 0) {
711
speed = MIN2(pedType->getMaxSpeed(), pedType->getDesiredMaxSpeed());
712
}
713
if (walkFactor < 0) {
714
walkFactor = OptionsCont::getOptions().getFloat("persontrip.walkfactor");
715
}
716
const double externalFactor = StringUtils::toDouble(pedType->getParameter().getParameter("externalEffortFactor", "100"));
717
if (departPos < 0) {
718
departPos += fromEdge->getLength();
719
}
720
if (arrivalPos == INVALID_DOUBLE_VALUE) {
721
arrivalPos = toEdge->getLength() / 2;
722
} else if (arrivalPos < 0) {
723
arrivalPos += toEdge->getLength();
724
}
725
if (departPos < 0 || departPos >= fromEdge->getLength()) {
726
throw TraCIException("Invalid depart position " + toString(departPos) + " for edge '" + from + "'.");
727
}
728
if (arrivalPos < 0 || arrivalPos >= toEdge->getLength()) {
729
throw TraCIException("Invalid arrival position " + toString(arrivalPos) + " for edge '" + to + "'.");
730
}
731
double minCost = std::numeric_limits<double>::max();
732
MSTransportableRouter& router = MSNet::getInstance()->getIntermodalRouter(0, routingMode);
733
for (SUMOVehicleParameter* vehPar : pars) {
734
std::vector<TraCIStage> resultCand;
735
SUMOVehicle* vehicle = nullptr;
736
if (vehPar != nullptr) {
737
MSVehicleType* type = MSNet::getInstance()->getVehicleControl().getVType(vehPar->vtypeid);
738
const bool isTaxi = type != nullptr && type->getID() == DEFAULT_TAXITYPE_ID && vehPar->line == "taxi";
739
if (type == nullptr) {
740
throw TraCIException("Unknown vehicle type '" + vehPar->vtypeid + "'.");
741
}
742
if (type->getVehicleClass() != SVC_IGNORING && (fromEdge->getPermissions() & type->getVehicleClass()) == 0 && !isTaxi) {
743
WRITE_WARNINGF(TL("Ignoring vehicle type '%' when performing intermodal routing because it is not allowed on the start edge '%'."), type->getID(), from);
744
} else {
745
ConstMSRoutePtr const routeDummy = std::make_shared<MSRoute>(vehPar->id, ConstMSEdgeVector({ fromEdge }), false, nullptr, StopParVector());
746
vehicle = vehControl.buildVehicle(vehPar, routeDummy, type, !MSGlobals::gCheckRoutes);
747
// we need to fix the speed factor here for deterministic results
748
vehicle->setChosenSpeedFactor(type->getSpeedFactor().getParameter(0));
749
}
750
}
751
std::vector<MSTransportableRouter::TripItem> items;
752
if (router.compute(fromEdge, toEdge, departPos, "", arrivalPos, destStop,
753
speed * walkFactor, vehicle, modeSet, departStep, items, externalFactor)) {
754
double cost = 0;
755
for (std::vector<MSTransportableRouter::TripItem>::iterator it = items.begin(); it != items.end(); ++it) {
756
if (!it->edges.empty()) {
757
resultCand.push_back(TraCIStage((it->line == "" ? STAGE_WALKING : STAGE_DRIVING), it->vType, it->line, it->destStop));
758
for (const MSEdge* e : it->edges) {
759
resultCand.back().edges.push_back(e->getID());
760
}
761
resultCand.back().travelTime = it->traveltime;
762
resultCand.back().cost = it->cost;
763
resultCand.back().length = it->length;
764
resultCand.back().intended = it->intended;
765
resultCand.back().depart = it->depart;
766
resultCand.back().departPos = it->departPos;
767
resultCand.back().arrivalPos = it->arrivalPos;
768
resultCand.back().description = it->description;
769
}
770
cost += it->cost;
771
}
772
if (cost < minCost) {
773
minCost = cost;
774
result = resultCand;
775
}
776
}
777
if (vehicle != nullptr) {
778
vehControl.deleteVehicle(vehicle, true);
779
vehControl.discountRoutingVehicle();
780
}
781
}
782
return result;
783
}
784
785
786
std::string
787
Simulation::getParameter(const std::string& objectID, const std::string& key) {
788
if (StringUtils::startsWith(key, "chargingStation.")) {
789
const std::string attrName = key.substr(16);
790
MSChargingStation* cs = static_cast<MSChargingStation*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_CHARGING_STATION));
791
if (cs == nullptr) {
792
throw TraCIException("Invalid chargingStation '" + objectID + "'");
793
}
794
if (attrName == toString(SUMO_ATTR_TOTALENERGYCHARGED)) {
795
return toString(cs->getTotalCharged());
796
} else if (attrName == toString(SUMO_ATTR_NAME)) {
797
return toString(cs->getMyName());
798
} else if (attrName == "lane") {
799
return cs->getLane().getID();
800
} else if (cs->hasParameter(attrName)) {
801
return cs->getParameter(attrName);
802
} else {
803
throw TraCIException("Invalid chargingStation parameter '" + attrName + "'");
804
}
805
} else if (StringUtils::startsWith(key, "overheadWire.")) {
806
const std::string attrName = key.substr(16);
807
MSOverheadWire* cs = static_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
808
if (cs == 0) {
809
throw TraCIException("Invalid overhead wire '" + objectID + "'");
810
}
811
if (attrName == toString(SUMO_ATTR_TOTALENERGYCHARGED)) {
812
return toString(cs->getTotalCharged());
813
} else if (attrName == toString(SUMO_ATTR_NAME)) {
814
return toString(cs->getMyName());
815
} else {
816
throw TraCIException("Invalid overhead wire parameter '" + attrName + "'");
817
}
818
} else if (StringUtils::startsWith(key, "net.")) {
819
const std::string attrName = key.substr(4);
820
if (attrName == toString(SUMO_ATTR_NET_OFFSET)) {
821
return toString(GeoConvHelper::getFinal().getOffsetBase());
822
} else {
823
throw TraCIException("Invalid net parameter '" + attrName + "'");
824
}
825
} else if (StringUtils::startsWith(key, "stats.")) {
826
if (objectID != "") {
827
throw TraCIException("Simulation parameter '" + key + "' is not supported for object id '" + objectID + "'. Use empty id for stats");
828
}
829
const std::string attrName = key.substr(6);
830
const MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
831
const MSTransportableControl* pc = MSNet::getInstance()->hasPersons() ? &MSNet::getInstance()->getPersonControl() : nullptr;
832
if (attrName == "vehicles.loaded") {
833
return toString(vc.getLoadedVehicleNo());
834
} else if (attrName == "vehicles.inserted") {
835
return toString(vc.getDepartedVehicleNo());
836
} else if (attrName == "vehicles.running") {
837
return toString(vc.getRunningVehicleNo());
838
} else if (attrName == "vehicles.waiting") {
839
return toString(MSNet::getInstance()->getInsertionControl().getWaitingVehicleNo());
840
} else if (attrName == "teleports.total") {
841
return toString(vc.getTeleportCount());
842
} else if (attrName == "teleports.jam") {
843
return toString(vc.getTeleportsJam());
844
} else if (attrName == "teleports.yield") {
845
return toString(vc.getTeleportsYield());
846
} else if (attrName == "teleports.wrongLane") {
847
return toString(vc.getTeleportsWrongLane());
848
} else if (attrName == "safety.collisions") {
849
return toString(vc.getCollisionCount());
850
} else if (attrName == "safety.emergencyStops") {
851
return toString(vc.getEmergencyStops());
852
} else if (attrName == "safety.emergencyBraking") {
853
return toString(vc.getEmergencyBrakingCount());
854
} else if (attrName == "persons.loaded") {
855
return toString(pc != nullptr ? pc->getLoadedNumber() : 0);
856
} else if (attrName == "persons.running") {
857
return toString(pc != nullptr ? pc->getRunningNumber() : 0);
858
} else if (attrName == "persons.jammed") {
859
return toString(pc != nullptr ? pc->getJammedNumber() : 0);
860
} else if (attrName == "personTeleports.total") {
861
return toString(pc != nullptr ? pc->getTeleportCount() : 0);
862
} else if (attrName == "personTeleports.abortWait") {
863
return toString(pc != nullptr ? pc->getTeleportsAbortWait() : 0);
864
} else if (attrName == "personTeleports.wrongDest") {
865
return toString(pc != nullptr ? pc->getTeleportsWrongDest() : 0);
866
} else {
867
throw TraCIException("Invalid stats parameter '" + attrName + "'");
868
}
869
} else if (StringUtils::startsWith(key, "parkingArea.")) {
870
const std::string attrName = key.substr(12);
871
MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_PARKING_AREA));
872
if (pa == nullptr) {
873
throw TraCIException("Invalid parkingArea '" + objectID + "'");
874
}
875
if (attrName == "capacity") {
876
return toString(pa->getCapacity());
877
} else if (attrName == "occupancy") {
878
return toString(pa->getOccupancyIncludingBlocked());
879
} else if (attrName == toString(SUMO_ATTR_NAME)) {
880
return toString(pa->getMyName());
881
} else if (attrName == "lane") {
882
return pa->getLane().getID();
883
} else if (pa->hasParameter(attrName)) {
884
return pa->getParameter(attrName);
885
} else {
886
throw TraCIException("Invalid parkingArea parameter '" + attrName + "'");
887
}
888
} else if (StringUtils::startsWith(key, "busStop.")) {
889
const std::string attrName = key.substr(8);
890
MSStoppingPlace* bs = static_cast<MSStoppingPlace*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_BUS_STOP));
891
if (bs == nullptr) {
892
throw TraCIException("Invalid busStop '" + objectID + "'");
893
}
894
if (attrName == toString(SUMO_ATTR_NAME)) {
895
return toString(bs->getMyName());
896
} else if (attrName == "lane") {
897
return bs->getLane().getID();
898
} else if (bs->hasParameter(attrName)) {
899
return bs->getParameter(attrName);
900
} else {
901
throw TraCIException("Invalid busStop parameter '" + attrName + "'");
902
}
903
} else if (StringUtils::startsWith(key, "device.tripinfo.")) {
904
if (objectID != "") {
905
throw TraCIException("Simulation parameter '" + key + "' is not supported for object id '" + objectID
906
+ "'. Use empty id for global device parameers or vehicle domain for vehicle specific parameters");
907
}
908
const std::string attrName = key.substr(16);
909
return MSDevice_Tripinfo::getGlobalParameter(attrName);
910
} else if (objectID == "") {
911
return MSNet::getInstance()->getParameter(key, "");
912
} else {
913
throw TraCIException("Simulation parameter '" + key + "' is not supported for object id '" + objectID + "'. Use empty id for generic network parameters");
914
}
915
}
916
917
LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Simulation)
918
919
void
920
Simulation::setParameter(const std::string& objectID, const std::string& key, const std::string& value) {
921
if (objectID == "") {
922
MSNet::getInstance()->setParameter(key, value);
923
} else {
924
throw TraCIException("Setting simulation parameter '" + key + "' is not supported for object id '" + objectID + "'. Use empty id for generic network parameters");
925
}
926
}
927
928
void
929
Simulation::setScale(double value) {
930
MSNet::getInstance()->getVehicleControl().setScale(value);
931
}
932
933
void
934
Simulation::clearPending(const std::string& routeID) {
935
MSNet::getInstance()->getInsertionControl().clearPendingVehicles(routeID);
936
}
937
938
939
void
940
Simulation::saveState(const std::string& fileName) {
941
MSStateHandler::saveState(fileName, MSNet::getInstance()->getCurrentTimeStep());
942
}
943
944
double
945
Simulation::loadState(const std::string& fileName) {
946
long before = PROGRESS_BEGIN_TIME_MESSAGE("Loading state from '" + fileName + "'");
947
try {
948
const SUMOTime newTime = MSNet::getInstance()->loadState(fileName, false);
949
Helper::clearStateChanges();
950
Helper::clearSubscriptions();
951
PROGRESS_TIME_MESSAGE(before);
952
return STEPS2TIME(newTime);
953
} catch (const IOError& e) {
954
throw TraCIException("Loading state from '" + fileName + "' failed. " + e.what());
955
} catch (const ProcessError& e) {
956
throw TraCIException("Loading state from '" + fileName + "' failed, check whether SUMO versions match. " + e.what());
957
}
958
}
959
960
void
961
Simulation::writeMessage(const std::string& msg) {
962
WRITE_MESSAGE(msg);
963
}
964
965
966
void
967
Simulation::storeShape(PositionVector& shape) {
968
shape = GeoConvHelper::getFinal().getConvBoundary().getShape(true);
969
}
970
971
972
std::shared_ptr<VariableWrapper>
973
Simulation::makeWrapper() {
974
return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
975
}
976
977
978
bool
979
Simulation::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
980
switch (variable) {
981
case VAR_TIME:
982
return wrapper->wrapDouble(objID, variable, getTime());
983
case VAR_TIME_STEP:
984
return wrapper->wrapInt(objID, variable, (int)getCurrentTime());
985
case VAR_END:
986
return wrapper->wrapDouble(objID, variable, getEndTime());
987
case VAR_LOADED_VEHICLES_NUMBER:
988
return wrapper->wrapInt(objID, variable, getLoadedNumber());
989
case VAR_LOADED_VEHICLES_IDS:
990
return wrapper->wrapStringList(objID, variable, getLoadedIDList());
991
case VAR_DEPARTED_VEHICLES_NUMBER:
992
return wrapper->wrapInt(objID, variable, getDepartedNumber());
993
case VAR_DEPARTED_VEHICLES_IDS:
994
return wrapper->wrapStringList(objID, variable, getDepartedIDList());
995
case VAR_TELEPORT_STARTING_VEHICLES_NUMBER:
996
return wrapper->wrapInt(objID, variable, getStartingTeleportNumber());
997
case VAR_TELEPORT_STARTING_VEHICLES_IDS:
998
return wrapper->wrapStringList(objID, variable, getStartingTeleportIDList());
999
case VAR_TELEPORT_ENDING_VEHICLES_NUMBER:
1000
return wrapper->wrapInt(objID, variable, getEndingTeleportNumber());
1001
case VAR_TELEPORT_ENDING_VEHICLES_IDS:
1002
return wrapper->wrapStringList(objID, variable, getEndingTeleportIDList());
1003
case VAR_ARRIVED_VEHICLES_NUMBER:
1004
return wrapper->wrapInt(objID, variable, getArrivedNumber());
1005
case VAR_ARRIVED_VEHICLES_IDS:
1006
return wrapper->wrapStringList(objID, variable, getArrivedIDList());
1007
case VAR_PARKING_STARTING_VEHICLES_NUMBER:
1008
return wrapper->wrapInt(objID, variable, getParkingStartingVehiclesNumber());
1009
case VAR_PARKING_STARTING_VEHICLES_IDS:
1010
return wrapper->wrapStringList(objID, variable, getParkingStartingVehiclesIDList());
1011
case VAR_PARKING_ENDING_VEHICLES_NUMBER:
1012
return wrapper->wrapInt(objID, variable, getParkingEndingVehiclesNumber());
1013
case VAR_PARKING_ENDING_VEHICLES_IDS:
1014
return wrapper->wrapStringList(objID, variable, getParkingEndingVehiclesIDList());
1015
case VAR_STOP_STARTING_VEHICLES_NUMBER:
1016
return wrapper->wrapInt(objID, variable, getStopStartingVehiclesNumber());
1017
case VAR_STOP_STARTING_VEHICLES_IDS:
1018
return wrapper->wrapStringList(objID, variable, getStopStartingVehiclesIDList());
1019
case VAR_STOP_ENDING_VEHICLES_NUMBER:
1020
return wrapper->wrapInt(objID, variable, getStopEndingVehiclesNumber());
1021
case VAR_STOP_ENDING_VEHICLES_IDS:
1022
return wrapper->wrapStringList(objID, variable, getStopEndingVehiclesIDList());
1023
case VAR_COLLIDING_VEHICLES_NUMBER:
1024
return wrapper->wrapInt(objID, variable, getCollidingVehiclesNumber());
1025
case VAR_COLLIDING_VEHICLES_IDS:
1026
return wrapper->wrapStringList(objID, variable, getCollidingVehiclesIDList());
1027
case VAR_EMERGENCYSTOPPING_VEHICLES_NUMBER:
1028
return wrapper->wrapInt(objID, variable, getEmergencyStoppingVehiclesNumber());
1029
case VAR_EMERGENCYSTOPPING_VEHICLES_IDS:
1030
return wrapper->wrapStringList(objID, variable, getEmergencyStoppingVehiclesIDList());
1031
case VAR_DEPARTED_PERSONS_NUMBER:
1032
return wrapper->wrapInt(objID, variable, getDepartedPersonNumber());
1033
case VAR_DEPARTED_PERSONS_IDS:
1034
return wrapper->wrapStringList(objID, variable, getDepartedPersonIDList());
1035
case VAR_ARRIVED_PERSONS_NUMBER:
1036
return wrapper->wrapInt(objID, variable, getArrivedPersonNumber());
1037
case VAR_ARRIVED_PERSONS_IDS:
1038
return wrapper->wrapStringList(objID, variable, getArrivedPersonIDList());
1039
case VAR_SCALE:
1040
return wrapper->wrapDouble(objID, variable, getScale());
1041
case VAR_DELTA_T:
1042
return wrapper->wrapDouble(objID, variable, getDeltaT());
1043
case VAR_OPTION:
1044
return wrapper->wrapString(objID, variable, getOption(objID));
1045
case VAR_MIN_EXPECTED_VEHICLES:
1046
return wrapper->wrapInt(objID, variable, getMinExpectedNumber());
1047
case VAR_BUS_STOP_ID_LIST:
1048
return wrapper->wrapStringList(objID, variable, getBusStopIDList());
1049
case VAR_BUS_STOP_WAITING:
1050
return wrapper->wrapInt(objID, variable, getBusStopWaiting(objID));
1051
case VAR_BUS_STOP_WAITING_IDS:
1052
return wrapper->wrapStringList(objID, variable, getBusStopWaitingIDList(objID));
1053
case VAR_PENDING_VEHICLES:
1054
return wrapper->wrapStringList(objID, variable, getPendingVehicles());
1055
case VAR_PARAMETER:
1056
return wrapper->wrapString(objID, variable, getParameter(objID, StoHelp::readTypedString(*paramData)));
1057
case VAR_PARAMETER_WITH_KEY:
1058
return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, StoHelp::readTypedString(*paramData)));
1059
default:
1060
return false;
1061
}
1062
}
1063
}
1064
1065
1066
/****************************************************************************/
1067
1068