Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/libsumo/Simulation.cpp
193693 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2017-2026 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,
603
double depart, int routingMode, double departPos, double arrivalPos) {
604
TraCIStage result(STAGE_DRIVING);
605
const MSEdge* const fromEdge = MSEdge::dictionary(from);
606
if (fromEdge == nullptr) {
607
throw TraCIException("Unknown from edge '" + from + "'.");
608
}
609
const MSEdge* const toEdge = MSEdge::dictionary(to);
610
if (toEdge == nullptr) {
611
throw TraCIException("Unknown to edge '" + to + "'.");
612
}
613
MSBaseVehicle* vehicle = nullptr;
614
MSVehicleType* type = MSNet::getInstance()->getVehicleControl().getVType(typeID == "" ? DEFAULT_VTYPE_ID : typeID);
615
if (type == nullptr) {
616
throw TraCIException("The vehicle type '" + typeID + "' is not known.");
617
}
618
SUMOVehicleParameter* pars = new SUMOVehicleParameter();
619
pars->id = "simulation.findRoute";
620
try {
621
ConstMSRoutePtr const routeDummy = std::make_shared<MSRoute>("", ConstMSEdgeVector({ fromEdge }), false, nullptr, StopParVector());
622
vehicle = dynamic_cast<MSBaseVehicle*>(MSNet::getInstance()->getVehicleControl().buildVehicle(pars, routeDummy, type, false));
623
std::string msg;
624
if (!vehicle->hasValidRouteStart(msg)) {
625
MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
626
MSNet::getInstance()->getVehicleControl().discountRoutingVehicle();
627
throw TraCIException("Invalid departure edge for vehicle type '" + type->getID() + "' (" + msg + ")");
628
}
629
// we need to fix the speed factor here for deterministic results
630
vehicle->setChosenSpeedFactor(type->getSpeedFactor().getParameter(0));
631
vehicle->setRoutingMode(routingMode);
632
} catch (ProcessError& e) {
633
throw TraCIException("Invalid departure edge for vehicle type '" + type->getID() + "' (" + e.what() + ")");
634
}
635
if (abs(departPos) > fromEdge->getLength()) {
636
throw TraCIException("Invalid departPos " + toString(departPos) + " on edge '" + fromEdge->getID() + " (length " + toString(fromEdge->getLength()) + ")");
637
}
638
if (departPos < 0) {
639
departPos += fromEdge->getLength();
640
}
641
if (arrivalPos == INVALID_DOUBLE_VALUE) {
642
arrivalPos = toEdge->getLength();
643
}
644
if (abs(arrivalPos) > toEdge->getLength()) {
645
throw TraCIException("Invalid arrivalPos " + toString(arrivalPos) + " on edge '" + toEdge->getID() + " (length " + toString(toEdge->getLength()) + ")");
646
}
647
if (arrivalPos < 0) {
648
arrivalPos += toEdge->getLength();
649
}
650
ConstMSEdgeVector edges;
651
const SUMOTime dep = depart < 0 ? MSNet::getInstance()->getCurrentTimeStep() : TIME2STEPS(depart);
652
SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = routingMode == ROUTING_MODE_AGGREGATED ? MSRoutingEngine::getRouterTT(0, vehicle->getVClass()) : MSNet::getInstance()->getRouterTT(0);
653
router.compute(fromEdge, departPos, toEdge, arrivalPos, vehicle, dep, edges);
654
for (const MSEdge* e : edges) {
655
result.edges.push_back(e->getID());
656
}
657
result.travelTime = result.cost = router.recomputeCostsPos(edges, vehicle, departPos, arrivalPos, dep, &result.length);
658
result.arrivalPos = arrivalPos;
659
result.departPos = departPos;
660
if (vehicle != nullptr) {
661
MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
662
MSNet::getInstance()->getVehicleControl().discountRoutingVehicle();
663
}
664
return result;
665
}
666
667
668
std::vector<TraCIStage>
669
Simulation::findIntermodalRoute(const std::string& from, const std::string& to,
670
const std::string& modes, double depart, const int routingMode, double speed, double walkFactor,
671
double departPos, double arrivalPos, const double departPosLat,
672
const std::string& pType, const std::string& vType, const std::string& destStop) {
673
UNUSED_PARAMETER(departPosLat);
674
std::vector<TraCIStage> result;
675
const MSEdge* const fromEdge = MSEdge::dictionary(from);
676
if (fromEdge == nullptr) {
677
throw TraCIException("Unknown from edge '" + from + "'.");
678
}
679
const MSEdge* const toEdge = MSEdge::dictionary(to);
680
if (toEdge == nullptr) {
681
throw TraCIException("Unknown to edge '" + to + "'.");
682
}
683
MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
684
SVCPermissions modeSet = 0;
685
std::vector<SUMOVehicleParameter*> pars;
686
if (vType != "") {
687
pars.push_back(new SUMOVehicleParameter());
688
pars.back()->vtypeid = vType;
689
pars.back()->id = vType;
690
modeSet |= SVC_PASSENGER;
691
}
692
for (StringTokenizer st(modes); st.hasNext();) {
693
const std::string mode = st.next();
694
if (mode == toString(PersonMode::CAR)) {
695
pars.push_back(new SUMOVehicleParameter());
696
pars.back()->vtypeid = DEFAULT_VTYPE_ID;
697
pars.back()->id = mode;
698
modeSet |= SVC_PASSENGER;
699
} else if (mode == toString(PersonMode::BICYCLE)) {
700
pars.push_back(new SUMOVehicleParameter());
701
pars.back()->vtypeid = DEFAULT_BIKETYPE_ID;
702
pars.back()->id = mode;
703
modeSet |= SVC_BICYCLE;
704
} else if (mode == toString(PersonMode::TAXI)) {
705
pars.push_back(new SUMOVehicleParameter());
706
pars.back()->vtypeid = DEFAULT_TAXITYPE_ID;
707
pars.back()->id = mode;
708
pars.back()->line = mode;
709
modeSet |= SVC_TAXI;
710
} else if (mode == toString(PersonMode::PUBLIC)) {
711
pars.push_back(nullptr);
712
modeSet |= SVC_BUS;
713
} else if (mode == toString(PersonMode::WALK)) {
714
// do nothing
715
} else {
716
throw TraCIException("Unknown person mode '" + mode + "'.");
717
}
718
}
719
if (pars.empty()) {
720
pars.push_back(nullptr);
721
}
722
// interpret default arguments
723
const MSVehicleType* pedType = vehControl.hasVType(pType) ? vehControl.getVType(pType) : vehControl.getVType(DEFAULT_PEDTYPE_ID);
724
SUMOTime departStep = TIME2STEPS(depart);
725
if (depart < 0) {
726
departStep = MSNet::getInstance()->getCurrentTimeStep();
727
}
728
if (speed < 0) {
729
speed = MIN2(pedType->getMaxSpeed(), pedType->getDesiredMaxSpeed());
730
}
731
if (walkFactor < 0) {
732
walkFactor = OptionsCont::getOptions().getFloat("persontrip.walkfactor");
733
}
734
const double externalFactor = StringUtils::toDouble(pedType->getParameter().getParameter("externalEffortFactor", "100"));
735
if (departPos < 0) {
736
departPos += fromEdge->getLength();
737
}
738
if (arrivalPos == INVALID_DOUBLE_VALUE) {
739
arrivalPos = toEdge->getLength() / 2;
740
} else if (arrivalPos < 0) {
741
arrivalPos += toEdge->getLength();
742
}
743
if (departPos < 0 || departPos >= fromEdge->getLength()) {
744
throw TraCIException("Invalid depart position " + toString(departPos) + " for edge '" + from + "'.");
745
}
746
if (arrivalPos < 0 || arrivalPos >= toEdge->getLength()) {
747
throw TraCIException("Invalid arrival position " + toString(arrivalPos) + " for edge '" + to + "'.");
748
}
749
double minCost = std::numeric_limits<double>::max();
750
MSTransportableRouter& router = MSNet::getInstance()->getIntermodalRouter(0, routingMode);
751
for (SUMOVehicleParameter* vehPar : pars) {
752
std::vector<TraCIStage> resultCand;
753
SUMOVehicle* vehicle = nullptr;
754
if (vehPar != nullptr) {
755
MSVehicleType* type = MSNet::getInstance()->getVehicleControl().getVType(vehPar->vtypeid);
756
const bool isTaxi = type != nullptr && type->getID() == DEFAULT_TAXITYPE_ID && vehPar->line == "taxi";
757
if (type == nullptr) {
758
throw TraCIException("Unknown vehicle type '" + vehPar->vtypeid + "'.");
759
}
760
if (type->getVehicleClass() != SVC_IGNORING && (fromEdge->getPermissions() & type->getVehicleClass()) == 0 && !isTaxi) {
761
WRITE_WARNINGF(TL("Ignoring vehicle type '%' when performing intermodal routing because it is not allowed on the start edge '%'."), type->getID(), from);
762
} else {
763
ConstMSRoutePtr const routeDummy = std::make_shared<MSRoute>(vehPar->id, ConstMSEdgeVector({ fromEdge }), false, nullptr, StopParVector());
764
vehicle = vehControl.buildVehicle(vehPar, routeDummy, type, !MSGlobals::gCheckRoutes);
765
// we need to fix the speed factor here for deterministic results
766
vehicle->setChosenSpeedFactor(type->getSpeedFactor().getParameter(0));
767
}
768
}
769
std::vector<MSTransportableRouter::TripItem> items;
770
if (router.compute(fromEdge, toEdge, departPos, "", arrivalPos, destStop,
771
speed * walkFactor, vehicle, pedType->getParameter(), modeSet, departStep, items, externalFactor)) {
772
double cost = 0;
773
for (std::vector<MSTransportableRouter::TripItem>::iterator it = items.begin(); it != items.end(); ++it) {
774
if (!it->edges.empty()) {
775
resultCand.push_back(TraCIStage((it->line == "" ? STAGE_WALKING : STAGE_DRIVING), it->vType, it->line, it->destStop));
776
for (const MSEdge* e : it->edges) {
777
resultCand.back().edges.push_back(e->getID());
778
}
779
resultCand.back().travelTime = it->traveltime;
780
resultCand.back().cost = it->cost;
781
resultCand.back().length = it->length;
782
resultCand.back().intended = it->intended;
783
resultCand.back().depart = it->depart;
784
resultCand.back().departPos = it->departPos;
785
resultCand.back().arrivalPos = it->arrivalPos;
786
resultCand.back().description = it->description;
787
}
788
cost += it->cost;
789
}
790
if (cost < minCost) {
791
minCost = cost;
792
result = resultCand;
793
}
794
}
795
if (vehicle != nullptr) {
796
vehControl.deleteVehicle(vehicle, true);
797
vehControl.discountRoutingVehicle();
798
}
799
}
800
return result;
801
}
802
803
804
std::string
805
Simulation::getParameter(const std::string& objectID, const std::string& key) {
806
if (StringUtils::startsWith(key, "chargingStation.")) {
807
const std::string attrName = key.substr(16);
808
MSChargingStation* cs = static_cast<MSChargingStation*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_CHARGING_STATION));
809
if (cs == nullptr) {
810
throw TraCIException("Invalid chargingStation '" + objectID + "'");
811
}
812
if (attrName == toString(SUMO_ATTR_TOTALENERGYCHARGED)) {
813
return toString(cs->getTotalCharged());
814
} else if (attrName == toString(SUMO_ATTR_NAME)) {
815
return toString(cs->getMyName());
816
} else if (attrName == "lane") {
817
return cs->getLane().getID();
818
} else if (cs->hasParameter(attrName)) {
819
return cs->getParameter(attrName);
820
} else {
821
throw TraCIException("Invalid chargingStation parameter '" + attrName + "'");
822
}
823
} else if (StringUtils::startsWith(key, "overheadWire.")) {
824
const std::string attrName = key.substr(16);
825
MSOverheadWire* cs = static_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
826
if (cs == 0) {
827
throw TraCIException("Invalid overhead wire '" + objectID + "'");
828
}
829
if (attrName == toString(SUMO_ATTR_TOTALENERGYCHARGED)) {
830
return toString(cs->getTotalCharged());
831
} else if (attrName == toString(SUMO_ATTR_NAME)) {
832
return toString(cs->getMyName());
833
} else {
834
throw TraCIException("Invalid overhead wire parameter '" + attrName + "'");
835
}
836
} else if (StringUtils::startsWith(key, "net.")) {
837
const std::string attrName = key.substr(4);
838
if (attrName == toString(SUMO_ATTR_NET_OFFSET)) {
839
return toString(GeoConvHelper::getFinal().getOffsetBase());
840
} else {
841
throw TraCIException("Invalid net parameter '" + attrName + "'");
842
}
843
} else if (StringUtils::startsWith(key, "stats.")) {
844
if (objectID != "") {
845
throw TraCIException("Simulation parameter '" + key + "' is not supported for object id '" + objectID + "'. Use empty id for stats");
846
}
847
const std::string attrName = key.substr(6);
848
const MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
849
const MSTransportableControl* pc = MSNet::getInstance()->hasPersons() ? &MSNet::getInstance()->getPersonControl() : nullptr;
850
if (attrName == "vehicles.loaded") {
851
return toString(vc.getLoadedVehicleNo());
852
} else if (attrName == "vehicles.inserted") {
853
return toString(vc.getDepartedVehicleNo());
854
} else if (attrName == "vehicles.running") {
855
return toString(vc.getRunningVehicleNo());
856
} else if (attrName == "vehicles.waiting") {
857
return toString(MSNet::getInstance()->getInsertionControl().getWaitingVehicleNo());
858
} else if (attrName == "teleports.total") {
859
return toString(vc.getTeleportCount());
860
} else if (attrName == "teleports.jam") {
861
return toString(vc.getTeleportsJam());
862
} else if (attrName == "teleports.yield") {
863
return toString(vc.getTeleportsYield());
864
} else if (attrName == "teleports.wrongLane") {
865
return toString(vc.getTeleportsWrongLane());
866
} else if (attrName == "safety.collisions") {
867
return toString(vc.getCollisionCount());
868
} else if (attrName == "safety.emergencyStops") {
869
return toString(vc.getEmergencyStops());
870
} else if (attrName == "safety.emergencyBraking") {
871
return toString(vc.getEmergencyBrakingCount());
872
} else if (attrName == "persons.loaded") {
873
return toString(pc != nullptr ? pc->getLoadedNumber() : 0);
874
} else if (attrName == "persons.running") {
875
return toString(pc != nullptr ? pc->getRunningNumber() : 0);
876
} else if (attrName == "persons.jammed") {
877
return toString(pc != nullptr ? pc->getJammedNumber() : 0);
878
} else if (attrName == "personTeleports.total") {
879
return toString(pc != nullptr ? pc->getTeleportCount() : 0);
880
} else if (attrName == "personTeleports.abortWait") {
881
return toString(pc != nullptr ? pc->getTeleportsAbortWait() : 0);
882
} else if (attrName == "personTeleports.wrongDest") {
883
return toString(pc != nullptr ? pc->getTeleportsWrongDest() : 0);
884
} else {
885
throw TraCIException("Invalid stats parameter '" + attrName + "'");
886
}
887
} else if (StringUtils::startsWith(key, "parkingArea.")) {
888
const std::string attrName = key.substr(12);
889
MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_PARKING_AREA));
890
if (pa == nullptr) {
891
throw TraCIException("Invalid parkingArea '" + objectID + "'");
892
}
893
if (attrName == "capacity") {
894
return toString(pa->getCapacity());
895
} else if (attrName == "occupancy") {
896
return toString(pa->getOccupancyIncludingBlocked());
897
} else if (attrName == toString(SUMO_ATTR_NAME)) {
898
return toString(pa->getMyName());
899
} else if (attrName == "lane") {
900
return pa->getLane().getID();
901
} else if (pa->hasParameter(attrName)) {
902
return pa->getParameter(attrName);
903
} else {
904
throw TraCIException("Invalid parkingArea parameter '" + attrName + "'");
905
}
906
} else if (StringUtils::startsWith(key, "busStop.")) {
907
const std::string attrName = key.substr(8);
908
MSStoppingPlace* bs = static_cast<MSStoppingPlace*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_BUS_STOP));
909
if (bs == nullptr) {
910
throw TraCIException("Invalid busStop '" + objectID + "'");
911
}
912
if (attrName == toString(SUMO_ATTR_NAME)) {
913
return toString(bs->getMyName());
914
} else if (attrName == "lane") {
915
return bs->getLane().getID();
916
} else if (bs->hasParameter(attrName)) {
917
return bs->getParameter(attrName);
918
} else {
919
throw TraCIException("Invalid busStop parameter '" + attrName + "'");
920
}
921
} else if (StringUtils::startsWith(key, "device.tripinfo.")) {
922
if (objectID != "") {
923
throw TraCIException("Simulation parameter '" + key + "' is not supported for object id '" + objectID
924
+ "'. Use empty id for global device parameers or vehicle domain for vehicle specific parameters");
925
}
926
const std::string attrName = key.substr(16);
927
return MSDevice_Tripinfo::getGlobalParameter(attrName);
928
} else if (objectID == "") {
929
return MSNet::getInstance()->getParameter(key, "");
930
} else {
931
throw TraCIException("Simulation parameter '" + key + "' is not supported for object id '" + objectID + "'. Use empty id for generic network parameters");
932
}
933
}
934
935
LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Simulation)
936
937
void
938
Simulation::setParameter(const std::string& objectID, const std::string& key, const std::string& value) {
939
if (objectID == "") {
940
MSNet::getInstance()->setParameter(key, value);
941
} else {
942
throw TraCIException("Setting simulation parameter '" + key + "' is not supported for object id '" + objectID + "'. Use empty id for generic network parameters");
943
}
944
}
945
946
void
947
Simulation::setScale(double value) {
948
MSNet::getInstance()->getVehicleControl().setScale(value);
949
}
950
951
void
952
Simulation::clearPending(const std::string& routeID) {
953
MSNet::getInstance()->getInsertionControl().clearPendingVehicles(routeID);
954
}
955
956
957
void
958
Simulation::saveState(const std::string& fileName) {
959
MSStateHandler::saveState(fileName, MSNet::getInstance()->getCurrentTimeStep());
960
}
961
962
double
963
Simulation::loadState(const std::string& fileName) {
964
long before = PROGRESS_BEGIN_TIME_MESSAGE("Loading state from '" + fileName + "'");
965
try {
966
const SUMOTime newTime = MSNet::getInstance()->loadState(fileName, false);
967
Helper::clearStateChanges();
968
Helper::clearSubscriptions();
969
PROGRESS_TIME_MESSAGE(before);
970
return STEPS2TIME(newTime);
971
} catch (const IOError& e) {
972
throw TraCIException("Loading state from '" + fileName + "' failed. " + e.what());
973
} catch (const ProcessError& e) {
974
throw TraCIException("Loading state from '" + fileName + "' failed, check whether SUMO versions match. " + e.what());
975
}
976
}
977
978
void
979
Simulation::writeMessage(const std::string& msg) {
980
WRITE_MESSAGE(msg);
981
}
982
983
984
void
985
Simulation::storeShape(PositionVector& shape) {
986
shape = GeoConvHelper::getFinal().getConvBoundary().getShape(true);
987
}
988
989
990
std::shared_ptr<VariableWrapper>
991
Simulation::makeWrapper() {
992
return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
993
}
994
995
996
bool
997
Simulation::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
998
switch (variable) {
999
case VAR_TIME:
1000
return wrapper->wrapDouble(objID, variable, getTime());
1001
case VAR_TIME_STEP:
1002
return wrapper->wrapInt(objID, variable, (int)getCurrentTime());
1003
case VAR_END:
1004
return wrapper->wrapDouble(objID, variable, getEndTime());
1005
case VAR_LOADED_VEHICLES_NUMBER:
1006
return wrapper->wrapInt(objID, variable, getLoadedNumber());
1007
case VAR_LOADED_VEHICLES_IDS:
1008
return wrapper->wrapStringList(objID, variable, getLoadedIDList());
1009
case VAR_DEPARTED_VEHICLES_NUMBER:
1010
return wrapper->wrapInt(objID, variable, getDepartedNumber());
1011
case VAR_DEPARTED_VEHICLES_IDS:
1012
return wrapper->wrapStringList(objID, variable, getDepartedIDList());
1013
case VAR_TELEPORT_STARTING_VEHICLES_NUMBER:
1014
return wrapper->wrapInt(objID, variable, getStartingTeleportNumber());
1015
case VAR_TELEPORT_STARTING_VEHICLES_IDS:
1016
return wrapper->wrapStringList(objID, variable, getStartingTeleportIDList());
1017
case VAR_TELEPORT_ENDING_VEHICLES_NUMBER:
1018
return wrapper->wrapInt(objID, variable, getEndingTeleportNumber());
1019
case VAR_TELEPORT_ENDING_VEHICLES_IDS:
1020
return wrapper->wrapStringList(objID, variable, getEndingTeleportIDList());
1021
case VAR_ARRIVED_VEHICLES_NUMBER:
1022
return wrapper->wrapInt(objID, variable, getArrivedNumber());
1023
case VAR_ARRIVED_VEHICLES_IDS:
1024
return wrapper->wrapStringList(objID, variable, getArrivedIDList());
1025
case VAR_PARKING_STARTING_VEHICLES_NUMBER:
1026
return wrapper->wrapInt(objID, variable, getParkingStartingVehiclesNumber());
1027
case VAR_PARKING_STARTING_VEHICLES_IDS:
1028
return wrapper->wrapStringList(objID, variable, getParkingStartingVehiclesIDList());
1029
case VAR_PARKING_ENDING_VEHICLES_NUMBER:
1030
return wrapper->wrapInt(objID, variable, getParkingEndingVehiclesNumber());
1031
case VAR_PARKING_ENDING_VEHICLES_IDS:
1032
return wrapper->wrapStringList(objID, variable, getParkingEndingVehiclesIDList());
1033
case VAR_STOP_STARTING_VEHICLES_NUMBER:
1034
return wrapper->wrapInt(objID, variable, getStopStartingVehiclesNumber());
1035
case VAR_STOP_STARTING_VEHICLES_IDS:
1036
return wrapper->wrapStringList(objID, variable, getStopStartingVehiclesIDList());
1037
case VAR_STOP_ENDING_VEHICLES_NUMBER:
1038
return wrapper->wrapInt(objID, variable, getStopEndingVehiclesNumber());
1039
case VAR_STOP_ENDING_VEHICLES_IDS:
1040
return wrapper->wrapStringList(objID, variable, getStopEndingVehiclesIDList());
1041
case VAR_COLLIDING_VEHICLES_NUMBER:
1042
return wrapper->wrapInt(objID, variable, getCollidingVehiclesNumber());
1043
case VAR_COLLIDING_VEHICLES_IDS:
1044
return wrapper->wrapStringList(objID, variable, getCollidingVehiclesIDList());
1045
case VAR_EMERGENCYSTOPPING_VEHICLES_NUMBER:
1046
return wrapper->wrapInt(objID, variable, getEmergencyStoppingVehiclesNumber());
1047
case VAR_EMERGENCYSTOPPING_VEHICLES_IDS:
1048
return wrapper->wrapStringList(objID, variable, getEmergencyStoppingVehiclesIDList());
1049
case VAR_DEPARTED_PERSONS_NUMBER:
1050
return wrapper->wrapInt(objID, variable, getDepartedPersonNumber());
1051
case VAR_DEPARTED_PERSONS_IDS:
1052
return wrapper->wrapStringList(objID, variable, getDepartedPersonIDList());
1053
case VAR_ARRIVED_PERSONS_NUMBER:
1054
return wrapper->wrapInt(objID, variable, getArrivedPersonNumber());
1055
case VAR_ARRIVED_PERSONS_IDS:
1056
return wrapper->wrapStringList(objID, variable, getArrivedPersonIDList());
1057
case VAR_SCALE:
1058
return wrapper->wrapDouble(objID, variable, getScale());
1059
case VAR_DELTA_T:
1060
return wrapper->wrapDouble(objID, variable, getDeltaT());
1061
case VAR_OPTION:
1062
return wrapper->wrapString(objID, variable, getOption(objID));
1063
case VAR_MIN_EXPECTED_VEHICLES:
1064
return wrapper->wrapInt(objID, variable, getMinExpectedNumber());
1065
case VAR_BUS_STOP_ID_LIST:
1066
return wrapper->wrapStringList(objID, variable, getBusStopIDList());
1067
case VAR_BUS_STOP_WAITING:
1068
return wrapper->wrapInt(objID, variable, getBusStopWaiting(objID));
1069
case VAR_BUS_STOP_WAITING_IDS:
1070
return wrapper->wrapStringList(objID, variable, getBusStopWaitingIDList(objID));
1071
case VAR_PENDING_VEHICLES:
1072
return wrapper->wrapStringList(objID, variable, getPendingVehicles());
1073
case VAR_PARAMETER:
1074
return wrapper->wrapString(objID, variable, getParameter(objID, StoHelp::readTypedString(*paramData)));
1075
case VAR_PARAMETER_WITH_KEY:
1076
return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, StoHelp::readTypedString(*paramData)));
1077
default:
1078
return false;
1079
}
1080
}
1081
}
1082
1083
1084
/****************************************************************************/
1085
1086